<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[52040] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/52040">52040</a></dd>
<dt>Author</dt> <dd>ggaren@apple.com</dd>
<dt>Date</dt> <dd>2009-12-11 21:29:56 -0800 (Fri, 11 Dec 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>JavaScriptCore: Changed GC from mark-sweep to mark-allocate.
        
Reviewed by Sam Weinig.

Added WeakGCMap to keep WebCore blissfully ignorant about objects that
have become garbage but haven't run their destructors yet.
        
1% SunSpider speedup.
7.6% v8 speedup (37% splay speedup).
17% speedup on bench-alloc-nonretained.js.
18% speedup on bench-alloc-retained.js.

* API/JSBase.cpp:
(JSGarbageCollect):
* API/JSContextRef.cpp:
* JavaScriptCore.exp:
* JavaScriptCore.xcodeproj/project.pbxproj: Updated for renames and new
files.

* debugger/Debugger.cpp:
(JSC::Debugger::recompileAllJSFunctions): Updated to use the Collector
iterator abstraction.

* jsc.cpp:
(functionGC): Updated for rename.

* runtime/Collector.cpp: Slightly reduced the number of allocations per
collection, so that small workloads only allocate on collector block,
rather than two.

(JSC::Heap::Heap): Updated to use the new allocateBlock function.

(JSC::Heap::destroy): Updated to use the new freeBlocks function.

(JSC::Heap::allocateBlock): New function to initialize a block when
allocating it.

(JSC::Heap::freeBlock): Consolidated the responsibility for running
destructors into this function.

(JSC::Heap::freeBlocks): Updated to use freeBlock.

(JSC::Heap::recordExtraCost): Sweep the heap in this reporting function,
so that allocation, which is more common, doesn't have to check extraCost.

(JSC::Heap::heapAllocate): Run destructors right before recycling a
garbage cell. This has better cache utilization than a separate sweep phase.

(JSC::Heap::resizeBlocks):
(JSC::Heap::growBlocks):
(JSC::Heap::shrinkBlocks): New set of functions for managing the size of
the heap, now that the heap doesn't maintain any information about its
size.

(JSC::isPointerAligned):
(JSC::isHalfCellAligned):
(JSC::isPossibleCell):
(JSC::isCellAligned):
(JSC::Heap::markConservatively): Cleaned up this code a bit.

(JSC::Heap::clearMarkBits):
(JSC::Heap::markedCells): Some helper functions for examining the the mark
bitmap.

(JSC::Heap::sweep): Simplified this function by using a DeadObjectIterator.

(JSC::Heap::markRoots): Reordered some operations for clarity.

(JSC::Heap::objectCount):
(JSC::Heap::addToStatistics):
(JSC::Heap::statistics): Rewrote these functions to calculate an object
count on demand, since the heap doesn't maintain this information by 
itself.

(JSC::Heap::reset): New function for resetting the heap once we've
exhausted heap space.

(JSC::Heap::collectAllGarbage): This function matches the old collect()
behavior, but it's now an uncommon function used only by API.

* runtime/Collector.h:
(JSC::CollectorBitmap::count):
(JSC::CollectorBitmap::isEmpty): Added some helper functions for managing
the collector mark bitmap.

(JSC::Heap::reportExtraMemoryCost): Changed reporting from cell equivalents
to bytes, so it's easier to understand.
        
* runtime/CollectorHeapIterator.h:
(JSC::CollectorHeapIterator::CollectorHeapIterator):
(JSC::CollectorHeapIterator::operator!=):
(JSC::CollectorHeapIterator::operator*):
(JSC::CollectorHeapIterator::advance):
(JSC::::LiveObjectIterator):
(JSC::::operator):
(JSC::::DeadObjectIterator):
(JSC::::ObjectIterator): New iterators for encapsulating details about
heap layout, and what's live and dead on the heap.

* runtime/JSArray.cpp:
(JSC::JSArray::putSlowCase):
(JSC::JSArray::increaseVectorLength): Delay reporting extra cost until
we're fully constructed, so the heap mark phase won't visit us in an
invalid state.

* runtime/JSCell.h:
(JSC::JSCell::):
(JSC::JSCell::createDummyStructure):
(JSC::JSCell::JSCell):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSGlobalData.h: Added a dummy cell to simplify allocation logic.

* runtime/JSString.h:
(JSC::jsSubstring): Don't report extra cost for substrings, since they
share a buffer that's already reported extra cost.

* runtime/Tracing.d:
* runtime/Tracing.h: Changed these dtrace hooks not to report object
counts, since they're no longer cheap to compute.

* runtime/UString.h: Updated for renames.

* runtime/WeakGCMap.h: Added.
(JSC::WeakGCMap::isEmpty):
(JSC::WeakGCMap::uncheckedGet):
(JSC::WeakGCMap::uncheckedBegin):
(JSC::WeakGCMap::uncheckedEnd):
(JSC::::get):
(JSC::::take):
(JSC::::set):
(JSC::::uncheckedRemove): Mentioned above.

* wtf/StdLibExtras.h:
(WTF::bitCount): Added a bit population count function, so the heap can
count live objects to fulfill statistics questions.

JavaScriptGlue: Changed GC from mark-sweep to mark-allocate.
        
Reviewed by Sam Weinig.

* JavaScriptGlue.cpp:
(JSCollect): Updated for rename. Fixed a bug where JSGlue would not check
to avoid nested GC calls.

WebCore: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

* ForwardingHeaders/runtime/WeakGCMap.h: Added.
* bindings/js/GCController.cpp:
(WebCore::collect):
(WebCore::GCController::gcTimerFired):
(WebCore::GCController::garbageCollectNow): Updated for rename.

* bindings/js/JSDOMBinding.cpp:
(WebCore::removeWrappers):
(WebCore::hasCachedDOMObjectWrapperUnchecked):
(WebCore::hasCachedDOMObjectWrapper):
(WebCore::hasCachedDOMNodeWrapperUnchecked):
(WebCore::forgetDOMObject):
(WebCore::forgetDOMNode):
(WebCore::isObservableThroughDOM):
(WebCore::markDOMNodesForDocument):
(WebCore::markDOMObjectWrapper):
(WebCore::markDOMNodeWrapper):
* bindings/js/JSDOMBinding.h: Changed DOM wrapper maps to be WeakGCMaps.
Don't ASSERT that an item must be in the WeakGCMap when its destructor
runs, since it might have been overwritten in the map first.

* bindings/js/JSDocumentCustom.cpp:
(WebCore::toJS): Changed Document from a DOM object wrapper to a DOM node
wrapper, to simplify some code.

* bindings/js/JSInspectedObjectWrapper.cpp:
(WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
(WebCore::JSInspectedObjectWrapper::~JSInspectedObjectWrapper):
* bindings/js/JSInspectorCallbackWrapper.cpp: Use a WeakGCMap for these
wrappers.

* bindings/js/JSNodeCustom.cpp:
(WebCore::JSNode::markChildren): Updated for WeakGCMap and Document using
a DOM node wrapper instead of a DOM object wrapper.

* bindings/js/JSSVGPODTypeWrapper.h:
(WebCore::JSSVGDynamicPODTypeWrapperCache::wrapperMap):
(WebCore::JSSVGDynamicPODTypeWrapperCache::lookupOrCreateWrapper):
(WebCore::JSSVGDynamicPODTypeWrapperCache::forgetWrapper):
(WebCore::::~JSSVGDynamicPODTypeWrapper): Shined a small beam of sanity
on this code. Use hashtable-based lookup in JSSVGPODTypeWrapper.h instead
of linear lookup through iteration, since that's what hashtables were
invented for. Make JSSVGPODTypeWrapper.h responsible for reomving itself
from the table, instead of its JS wrapper, to decouple these objects from
GC, and because these objects are refCounted, not solely owned by their
JS wrappers.

* bindings/scripts/CodeGeneratorJS.pm:
* dom/Document.h: Adopted changes above.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJavaScriptCoreAPIJSBasecpp">trunk/JavaScriptCore/API/JSBase.cpp</a></li>
<li><a href="#trunkJavaScriptCoreAPIJSContextRefcpp">trunk/JavaScriptCore/API/JSContextRef.cpp</a></li>
<li><a href="#trunkJavaScriptCoreChangeLog">trunk/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkJavaScriptCoreJavaScriptCoreexp">trunk/JavaScriptCore/JavaScriptCore.exp</a></li>
<li><a href="#trunkJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkJavaScriptCoredebuggerDebuggercpp">trunk/JavaScriptCore/debugger/Debugger.cpp</a></li>
<li><a href="#trunkJavaScriptCorejsccpp">trunk/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeCollectorcpp">trunk/JavaScriptCore/runtime/Collector.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeCollectorh">trunk/JavaScriptCore/runtime/Collector.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeCollectorHeapIteratorh">trunk/JavaScriptCore/runtime/CollectorHeapIterator.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSArraycpp">trunk/JavaScriptCore/runtime/JSArray.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSCellh">trunk/JavaScriptCore/runtime/JSCell.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSGlobalDatacpp">trunk/JavaScriptCore/runtime/JSGlobalData.cpp</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSGlobalDatah">trunk/JavaScriptCore/runtime/JSGlobalData.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeJSStringh">trunk/JavaScriptCore/runtime/JSString.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeTracingd">trunk/JavaScriptCore/runtime/Tracing.d</a></li>
<li><a href="#trunkJavaScriptCoreruntimeTracingh">trunk/JavaScriptCore/runtime/Tracing.h</a></li>
<li><a href="#trunkJavaScriptCoreruntimeUStringh">trunk/JavaScriptCore/runtime/UString.h</a></li>
<li><a href="#trunkJavaScriptCorewtfStdLibExtrash">trunk/JavaScriptCore/wtf/StdLibExtras.h</a></li>
<li><a href="#trunkJavaScriptGlueChangeLog">trunk/JavaScriptGlue/ChangeLog</a></li>
<li><a href="#trunkJavaScriptGlueJavaScriptGluecpp">trunk/JavaScriptGlue/JavaScriptGlue.cpp</a></li>
<li><a href="#trunkWebCoreChangeLog">trunk/WebCore/ChangeLog</a></li>
<li><a href="#trunkWebCorebindingsjsGCControllercpp">trunk/WebCore/bindings/js/GCController.cpp</a></li>
<li><a href="#trunkWebCorebindingsjsJSDOMBindingcpp">trunk/WebCore/bindings/js/JSDOMBinding.cpp</a></li>
<li><a href="#trunkWebCorebindingsjsJSDOMBindingh">trunk/WebCore/bindings/js/JSDOMBinding.h</a></li>
<li><a href="#trunkWebCorebindingsjsJSDocumentCustomcpp">trunk/WebCore/bindings/js/JSDocumentCustom.cpp</a></li>
<li><a href="#trunkWebCorebindingsjsJSInspectedObjectWrappercpp">trunk/WebCore/bindings/js/JSInspectedObjectWrapper.cpp</a></li>
<li><a href="#trunkWebCorebindingsjsJSInspectorCallbackWrappercpp">trunk/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp</a></li>
<li><a href="#trunkWebCorebindingsjsJSNodeCustomcpp">trunk/WebCore/bindings/js/JSNodeCustom.cpp</a></li>
<li><a href="#trunkWebCorebindingsjsJSSVGPODTypeWrapperh">trunk/WebCore/bindings/js/JSSVGPODTypeWrapper.h</a></li>
<li><a href="#trunkWebCorebindingsscriptsCodeGeneratorJSpm">trunk/WebCore/bindings/scripts/CodeGeneratorJS.pm</a></li>
<li><a href="#trunkWebCoredomDocumenth">trunk/WebCore/dom/Document.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/JavaScriptCore/JavaScriptCore/</li>
<li>trunk/JavaScriptCore/JavaScriptCore/runtime/</li>
<li><a href="#trunkJavaScriptCoreruntimeWeakGCMaph">trunk/JavaScriptCore/runtime/WeakGCMap.h</a></li>
<li><a href="#trunkWebCoreForwardingHeadersruntimeWeakGCMaph">trunk/WebCore/ForwardingHeaders/runtime/WeakGCMap.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJavaScriptCoreAPIJSBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/API/JSBase.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/API/JSBase.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/API/JSBase.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -99,7 +99,7 @@
</span><span class="cx">     JSLock lock(globalData.isSharedInstance ? LockForReal : SilenceAssertionsOnly);
</span><span class="cx"> 
</span><span class="cx">     if (!globalData.heap.isBusy())
</span><del>-        globalData.heap.collect();
</del><ins>+        globalData.heap.collectAllGarbage();
</ins><span class="cx"> 
</span><span class="cx">     // FIXME: Perhaps we should trigger a second mark and sweep
</span><span class="cx">     // once the garbage collector is done if this is called when
</span></span></pre></div>
<a id="trunkJavaScriptCoreAPIJSContextRefcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/API/JSContextRef.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/API/JSContextRef.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/API/JSContextRef.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -133,7 +133,7 @@
</span><span class="cx">         ASSERT(!globalData.heap.isBusy());
</span><span class="cx">         globalData.heap.destroy();
</span><span class="cx">     } else
</span><del>-        globalData.heap.collect();
</del><ins>+        globalData.heap.collectAllGarbage();
</ins><span class="cx"> 
</span><span class="cx">     globalData.deref();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/ChangeLog (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/ChangeLog        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/ChangeLog        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -1,3 +1,142 @@
</span><ins>+2009-12-11  Geoffrey Garen  &lt;ggaren@apple.com&gt;
+
+        Reviewed by Sam Weinig.
+        
+        Changed GC from mark-sweep to mark-allocate.
+        
+        Added WeakGCMap to keep WebCore blissfully ignorant about objects that
+        have become garbage but haven't run their destructors yet.
+        
+        1% SunSpider speedup.
+        7.6% v8 speedup (37% splay speedup).
+        17% speedup on bench-alloc-nonretained.js.
+        18% speedup on bench-alloc-retained.js.
+
+        * API/JSBase.cpp:
+        (JSGarbageCollect):
+        * API/JSContextRef.cpp:
+        * JavaScriptCore.exp:
+        * JavaScriptCore.xcodeproj/project.pbxproj: Updated for renames and new
+        files.
+
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::recompileAllJSFunctions): Updated to use the Collector
+        iterator abstraction.
+
+        * jsc.cpp:
+        (functionGC): Updated for rename.
+
+        * runtime/Collector.cpp: Slightly reduced the number of allocations per
+        collection, so that small workloads only allocate on collector block,
+        rather than two.
+
+        (JSC::Heap::Heap): Updated to use the new allocateBlock function.
+
+        (JSC::Heap::destroy): Updated to use the new freeBlocks function.
+
+        (JSC::Heap::allocateBlock): New function to initialize a block when
+        allocating it.
+
+        (JSC::Heap::freeBlock): Consolidated the responsibility for running
+        destructors into this function.
+
+        (JSC::Heap::freeBlocks): Updated to use freeBlock.
+
+        (JSC::Heap::recordExtraCost): Sweep the heap in this reporting function,
+        so that allocation, which is more common, doesn't have to check extraCost.
+
+        (JSC::Heap::heapAllocate): Run destructors right before recycling a
+        garbage cell. This has better cache utilization than a separate sweep phase.
+
+        (JSC::Heap::resizeBlocks):
+        (JSC::Heap::growBlocks):
+        (JSC::Heap::shrinkBlocks): New set of functions for managing the size of
+        the heap, now that the heap doesn't maintain any information about its
+        size.
+
+        (JSC::isPointerAligned):
+        (JSC::isHalfCellAligned):
+        (JSC::isPossibleCell):
+        (JSC::isCellAligned):
+        (JSC::Heap::markConservatively): Cleaned up this code a bit.
+
+        (JSC::Heap::clearMarkBits):
+        (JSC::Heap::markedCells): Some helper functions for examining the the mark
+        bitmap.
+
+        (JSC::Heap::sweep): Simplified this function by using a DeadObjectIterator.
+
+        (JSC::Heap::markRoots): Reordered some operations for clarity.
+
+        (JSC::Heap::objectCount):
+        (JSC::Heap::addToStatistics):
+        (JSC::Heap::statistics): Rewrote these functions to calculate an object
+        count on demand, since the heap doesn't maintain this information by 
+        itself.
+
+        (JSC::Heap::reset): New function for resetting the heap once we've
+        exhausted heap space.
+
+        (JSC::Heap::collectAllGarbage): This function matches the old collect()
+        behavior, but it's now an uncommon function used only by API.
+
+        * runtime/Collector.h:
+        (JSC::CollectorBitmap::count):
+        (JSC::CollectorBitmap::isEmpty): Added some helper functions for managing
+        the collector mark bitmap.
+
+        (JSC::Heap::reportExtraMemoryCost): Changed reporting from cell equivalents
+        to bytes, so it's easier to understand.
+        
+        * runtime/CollectorHeapIterator.h:
+        (JSC::CollectorHeapIterator::CollectorHeapIterator):
+        (JSC::CollectorHeapIterator::operator!=):
+        (JSC::CollectorHeapIterator::operator*):
+        (JSC::CollectorHeapIterator::advance):
+        (JSC::::LiveObjectIterator):
+        (JSC::::operator):
+        (JSC::::DeadObjectIterator):
+        (JSC::::ObjectIterator): New iterators for encapsulating details about
+        heap layout, and what's live and dead on the heap.
+
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::putSlowCase):
+        (JSC::JSArray::increaseVectorLength): Delay reporting extra cost until
+        we're fully constructed, so the heap mark phase won't visit us in an
+        invalid state.
+
+        * runtime/JSCell.h:
+        (JSC::JSCell::):
+        (JSC::JSCell::createDummyStructure):
+        (JSC::JSCell::JSCell):
+        * runtime/JSGlobalData.cpp:
+        (JSC::JSGlobalData::JSGlobalData):
+        * runtime/JSGlobalData.h: Added a dummy cell to simplify allocation logic.
+
+        * runtime/JSString.h:
+        (JSC::jsSubstring): Don't report extra cost for substrings, since they
+        share a buffer that's already reported extra cost.
+
+        * runtime/Tracing.d:
+        * runtime/Tracing.h: Changed these dtrace hooks not to report object
+        counts, since they're no longer cheap to compute.
+
+        * runtime/UString.h: Updated for renames.
+
+        * runtime/WeakGCMap.h: Added.
+        (JSC::WeakGCMap::isEmpty):
+        (JSC::WeakGCMap::uncheckedGet):
+        (JSC::WeakGCMap::uncheckedBegin):
+        (JSC::WeakGCMap::uncheckedEnd):
+        (JSC::::get):
+        (JSC::::take):
+        (JSC::::set):
+        (JSC::::uncheckedRemove): Mentioned above.
+
+        * wtf/StdLibExtras.h:
+        (WTF::bitCount): Added a bit population count function, so the heap can
+        count live objects to fulfill statistics questions.
+
</ins><span class="cx"> 2009-12-11  Gavin Barraclough  &lt;barraclough@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Oliver Hunt.
</span></span></pre></div>
<a id="trunkJavaScriptCoreJavaScriptCoreexp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/JavaScriptCore.exp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/JavaScriptCore.exp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/JavaScriptCore.exp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -180,16 +180,15 @@
</span><span class="cx"> __ZN3JSC25evaluateInGlobalCallFrameERKNS_7UStringERNS_7JSValueEPNS_14JSGlobalObjectE
</span><span class="cx"> __ZN3JSC35createInterruptedExecutionExceptionEPNS_12JSGlobalDataE
</span><span class="cx"> __ZN3JSC3NaNE
</span><del>-__ZN3JSC4Heap11objectCountEv
</del><span class="cx"> __ZN3JSC4Heap14primaryHeapEndEv
</span><span class="cx"> __ZN3JSC4Heap15recordExtraCostEm
</span><span class="cx"> __ZN3JSC4Heap16primaryHeapBeginEv
</span><ins>+__ZN3JSC4Heap17collectAllGarbageEv
</ins><span class="cx"> __ZN3JSC4Heap17globalObjectCountEv
</span><span class="cx"> __ZN3JSC4Heap20protectedObjectCountEv
</span><span class="cx"> __ZN3JSC4Heap25protectedObjectTypeCountsEv
</span><span class="cx"> __ZN3JSC4Heap26protectedGlobalObjectCountEv
</span><span class="cx"> __ZN3JSC4Heap6isBusyEv
</span><del>-__ZN3JSC4Heap7collectEv
</del><span class="cx"> __ZN3JSC4Heap7destroyEv
</span><span class="cx"> __ZN3JSC4Heap7protectENS_7JSValueE
</span><span class="cx"> __ZN3JSC4Heap8allocateEm
</span><span class="lines">@@ -368,6 +367,7 @@
</span><span class="cx"> __ZNK3JSC18PropertyDescriptor6setterEv
</span><span class="cx"> __ZNK3JSC18PropertyDescriptor8writableEv
</span><span class="cx"> __ZNK3JSC4Heap10statisticsEv
</span><ins>+__ZNK3JSC4Heap11objectCountEv
</ins><span class="cx"> __ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
</span><span class="cx"> __ZNK3JSC6JSCell12toThisObjectEPNS_9ExecStateE
</span><span class="cx"> __ZNK3JSC6JSCell12toThisStringEPNS_9ExecStateE
</span></span></pre></div>
<a id="trunkJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -167,6 +167,7 @@
</span><span class="cx">                 14BD59C50A3E8F9F00BAF59C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; };
</span><span class="cx">                 14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A290A3E91F600BAF59C /* JSContextRef.cpp */; };
</span><span class="cx">                 14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */; };
</span><ins>+                14BFCE6910CDB1FC00364CCE /* WeakGCMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A6581A0F4E36F4000150FD /* JITStubs.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 14E9D17B107EC469004DDA21 /* JSGlobalObjectFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */; };
</span><span class="cx">                 14F3488F0E95EF8A003648BC /* CollectorHeapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F3488E0E95EF8A003648BC /* CollectorHeapIterator.h */; settings = {ATTRIBUTES = (); }; };
</span><span class="lines">@@ -636,6 +637,7 @@
</span><span class="cx">                 14BD5A2A0A3E91F600BAF59C /* JSContextRef.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSContextRef.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSValueRef.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 14BD5A2D0A3E91F600BAF59C /* testapi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testapi.c; path = API/tests/testapi.c; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMap.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 14D792640DAA03FB001A9F05 /* RegisterFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterFile.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/tests/testapi.js; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -1602,6 +1604,7 @@
</span><span class="cx">                                 F692A8850255597D01FF60F7 /* UString.cpp */,
</span><span class="cx">                                 F692A8860255597D01FF60F7 /* UString.h */,
</span><span class="cx">                                 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
</span><ins>+                                14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
</ins><span class="cx">                                 A7C2216810C745E000F97913 /* JSZombie.h */,
</span><span class="cx">                                 A7C2216B10C7469C00F97913 /* JSZombie.cpp */,
</span><span class="cx">                         );
</span><span class="lines">@@ -2010,6 +2013,7 @@
</span><span class="cx">                                 86CAFEE31035DDE60028A609 /* Executable.h in Headers */,
</span><span class="cx">                                 142D3939103E4560007DCB52 /* NumericStrings.h in Headers */,
</span><span class="cx">                                 A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */,
</span><ins>+                                14BFCE6910CDB1FC00364CCE /* WeakGCMap.h in Headers */,
</ins><span class="cx">                                 BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */,
</span><span class="cx">                                 148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */,
</span><span class="cx">                                 14A1563210966365006FA260 /* DateInstanceCache.h in Headers */,
</span></span></pre></div>
<a id="trunkJavaScriptCoredebuggerDebuggercpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/debugger/Debugger.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/debugger/Debugger.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/debugger/Debugger.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -67,8 +67,9 @@
</span><span class="cx">     FunctionExecutableSet functionExecutables;
</span><span class="cx">     SourceProviderMap sourceProviders;
</span><span class="cx"> 
</span><del>-    Heap::iterator heapEnd = globalData-&gt;heap.primaryHeapEnd();
-    for (Heap::iterator it = globalData-&gt;heap.primaryHeapBegin(); it != heapEnd; ++it) {
</del><ins>+    LiveObjectIterator&lt;PrimaryHeap&gt; it = globalData-&gt;heap.primaryHeapBegin();
+    LiveObjectIterator&lt;PrimaryHeap&gt; heapEnd = globalData-&gt;heap.primaryHeapEnd();
+    for ( ; it != heapEnd; ++it) {
</ins><span class="cx">         if (!(*it)-&gt;inherits(&amp;JSFunction::info))
</span><span class="cx">             continue;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/jsc.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/jsc.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/jsc.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -194,7 +194,7 @@
</span><span class="cx"> JSValue JSC_HOST_CALL functionGC(ExecState* exec, JSObject*, JSValue, const ArgList&amp;)
</span><span class="cx"> {
</span><span class="cx">     JSLock lock(SilenceAssertionsOnly);
</span><del>-    exec-&gt;heap()-&gt;collect();
</del><ins>+    exec-&gt;heap()-&gt;collectAllGarbage();
</ins><span class="cx">     return jsUndefined();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeCollectorcpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/Collector.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/Collector.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/Collector.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -104,7 +104,7 @@
</span><span class="cx"> 
</span><span class="cx"> const size_t GROWTH_FACTOR = 2;
</span><span class="cx"> const size_t LOW_WATER_FACTOR = 4;
</span><del>-const size_t ALLOCATIONS_PER_COLLECTION = 4000;
</del><ins>+const size_t ALLOCATIONS_PER_COLLECTION = 3600;
</ins><span class="cx"> // This value has to be a macro to be used in max() without introducing
</span><span class="cx"> // a PIC branch in Mach-O binaries, see &lt;rdar://problem/5971391&gt;.
</span><span class="cx"> #define MIN_ARRAY_SIZE (static_cast&lt;size_t&gt;(14))
</span><span class="lines">@@ -148,7 +148,7 @@
</span><span class="cx">     , m_globalData(globalData)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(globalData);
</span><del>-
</del><ins>+    
</ins><span class="cx"> #if PLATFORM(SYMBIAN)
</span><span class="cx">     // Symbian OpenC supports mmap but currently not the MAP_ANON flag.
</span><span class="cx">     // Using fastMalloc() does not properly align blocks on 64k boundaries
</span><span class="lines">@@ -170,7 +170,12 @@
</span><span class="cx"> #endif // PLATFORM(SYMBIAN)
</span><span class="cx">     
</span><span class="cx">     memset(&amp;primaryHeap, 0, sizeof(CollectorHeap));
</span><ins>+    allocateBlock&lt;PrimaryHeap&gt;();
+
</ins><span class="cx">     memset(&amp;numberHeap, 0, sizeof(CollectorHeap));
</span><ins>+#if USE(JSVALUE32)
+    allocateBlock&lt;NumberHeap&gt;();
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Heap::~Heap()
</span><span class="lines">@@ -193,15 +198,8 @@
</span><span class="cx">     delete m_markListSet;
</span><span class="cx">     m_markListSet = 0;
</span><span class="cx"> 
</span><del>-    sweep&lt;PrimaryHeap&gt;();
-    // No need to sweep number heap, because the JSNumber destructor doesn't do anything.
-#if ENABLE(JSC_ZOMBIES)
-    ASSERT(primaryHeap.numLiveObjects == primaryHeap.numZombies);
-#else
-    ASSERT(!primaryHeap.numLiveObjects);
-#endif
-    freeBlocks(&amp;primaryHeap);
-    freeBlocks(&amp;numberHeap);
</del><ins>+    freeBlocks&lt;PrimaryHeap&gt;();
+    freeBlocks&lt;NumberHeap&gt;();
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(JSC_MULTIPLE_THREADS)
</span><span class="cx">     if (m_currentThreadRegistrar) {
</span><span class="lines">@@ -225,7 +223,6 @@
</span><span class="cx"> {
</span><span class="cx"> #if PLATFORM(DARWIN)
</span><span class="cx">     vm_address_t address = 0;
</span><del>-    // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: &lt;rdar://problem/6054788&gt;.
</del><span class="cx">     vm_map(current_task(), &amp;address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE | VM_TAG_FOR_COLLECTOR_MEMORY, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
</span><span class="cx"> #elif PLATFORM(SYMBIAN)
</span><span class="cx">     // Allocate a 64 kb aligned CollectorBlock
</span><span class="lines">@@ -233,8 +230,6 @@
</span><span class="cx">     if (!mask)
</span><span class="cx">         CRASH();
</span><span class="cx">     uintptr_t address = reinterpret_cast&lt;uintptr_t&gt;(mask);
</span><del>-
-    memset(reinterpret_cast&lt;void*&gt;(address), 0, BLOCK_SIZE);
</del><span class="cx"> #elif PLATFORM(WINCE)
</span><span class="cx">     void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
</span><span class="cx"> #elif PLATFORM(WIN_OS)
</span><span class="lines">@@ -247,7 +242,6 @@
</span><span class="cx"> #elif HAVE(POSIX_MEMALIGN)
</span><span class="cx">     void* address;
</span><span class="cx">     posix_memalign(&amp;address, BLOCK_SIZE, BLOCK_SIZE);
</span><del>-    memset(address, 0, BLOCK_SIZE);
</del><span class="cx"> #else
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JSC_MULTIPLE_THREADS)
</span><span class="lines">@@ -273,14 +267,23 @@
</span><span class="cx">         munmap(reinterpret_cast&lt;char*&gt;(address + adjust + BLOCK_SIZE), extra - adjust);
</span><span class="cx"> 
</span><span class="cx">     address += adjust;
</span><del>-    memset(reinterpret_cast&lt;void*&gt;(address), 0, BLOCK_SIZE);
</del><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    // Initialize block.
+
</ins><span class="cx">     CollectorBlock* block = reinterpret_cast&lt;CollectorBlock*&gt;(address);
</span><del>-    block-&gt;freeList = block-&gt;cells;
</del><span class="cx">     block-&gt;heap = this;
</span><span class="cx">     block-&gt;type = heapType;
</span><ins>+    clearMarkBits&lt;heapType&gt;(block);
</ins><span class="cx"> 
</span><ins>+    // heapAllocate assumes that it's safe to call a destructor on any cell in the primary heap.
+    if (heapType != NumberHeap) {
+        for (size_t i = 0; i &lt; HeapConstants&lt;heapType&gt;::cellsPerBlock; ++i)
+            new (block-&gt;cells + i) JSCell(JSCell::DummyDestructableCell);
+    }
+    
+    // Add block to blocks vector.
+
</ins><span class="cx">     CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
</span><span class="cx">     size_t numBlocks = heap.numBlocks;
</span><span class="cx">     if (heap.usedBlocks == numBlocks) {
</span><span class="lines">@@ -301,6 +304,12 @@
</span><span class="cx"> {
</span><span class="cx">     CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
</span><span class="cx"> 
</span><ins>+    if (heapType != NumberHeap) {
+        ObjectIterator&lt;heapType&gt; it(heap, block);
+        ObjectIterator&lt;heapType&gt; end(heap, block + 1);
+        for ( ; it != end; ++it)
+            (*it)-&gt;~JSCell();
+    }
</ins><span class="cx">     freeBlock(heap.blocks[block]);
</span><span class="cx"> 
</span><span class="cx">     // swap with the last block so we compact as we go
</span><span class="lines">@@ -334,13 +343,15 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::freeBlocks(CollectorHeap* heap)
</del><ins>+template &lt;HeapType heapType&gt;
+void Heap::freeBlocks()
</ins><span class="cx"> {
</span><del>-    for (size_t i = 0; i &lt; heap-&gt;usedBlocks; ++i)
-        if (heap-&gt;blocks[i])
-            freeBlock(heap-&gt;blocks[i]);
-    fastFree(heap-&gt;blocks);
-    memset(heap, 0, sizeof(CollectorHeap));
</del><ins>+    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+
+    while (heap.usedBlocks)
+        freeBlock&lt;heapType&gt;(0);
+    fastFree(heap.blocks);
+    memset(&amp;heap, 0, sizeof(CollectorHeap));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::recordExtraCost(size_t cost)
</span><span class="lines">@@ -357,6 +368,14 @@
</span><span class="cx">     // collecting more frequently as long as it stays alive.
</span><span class="cx">     // NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost 
</span><span class="cx"> 
</span><ins>+    if (primaryHeap.extraCost &gt; maxExtraCost &amp;&amp; primaryHeap.extraCost &gt; primaryHeap.usedBlocks * BLOCK_SIZE / 2) {
+        // If the last iteration through the heap deallocated blocks, we need
+        // to clean up remaining garbage before marking. Otherwise, the conservative
+        // marking mechanism might follow a pointer to unmapped memory.
+        if (primaryHeap.didShrink)
+            sweep&lt;PrimaryHeap&gt;();
+        reset();
+    }
</ins><span class="cx">     primaryHeap.extraCost += cost;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -364,101 +383,101 @@
</span><span class="cx"> {
</span><span class="cx">     typedef typename HeapConstants&lt;heapType&gt;::Block Block;
</span><span class="cx">     typedef typename HeapConstants&lt;heapType&gt;::Cell Cell;
</span><ins>+    
+    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
</ins><span class="cx"> 
</span><del>-    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
</del><span class="cx">     ASSERT(JSLock::lockCount() &gt; 0);
</span><span class="cx">     ASSERT(JSLock::currentThreadIsHoldingLock());
</span><span class="cx">     ASSERT_UNUSED(s, s &lt;= HeapConstants&lt;heapType&gt;::cellSize);
</span><span class="cx"> 
</span><span class="cx">     ASSERT(heap.operationInProgress == NoOperation);
</span><span class="cx">     ASSERT(heapType == PrimaryHeap || heap.extraCost == 0);
</span><del>-    // FIXME: If another global variable access here doesn't hurt performance
-    // too much, we could CRASH() in NDEBUG builds, which could help ensure we
-    // don't spend any time debugging cases where we allocate inside an object's
-    // deallocation code.
</del><span class="cx"> 
</span><span class="cx"> #if COLLECT_ON_EVERY_ALLOCATION
</span><del>-    collect();
</del><ins>+    collectAllGarbage();
+    ASSERT(heap.operationInProgress == NoOperation);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    size_t numLiveObjects = heap.numLiveObjects;
-    size_t usedBlocks = heap.usedBlocks;
-    size_t i = heap.firstBlockWithPossibleSpace;
</del><ins>+allocate:
</ins><span class="cx"> 
</span><del>-    // if we have a huge amount of extra cost, we'll try to collect even if we still have
-    // free cells left.
-    if (heapType == PrimaryHeap &amp;&amp; heap.extraCost &gt; ALLOCATIONS_PER_COLLECTION) {
-        size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
-        size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
-        const size_t newCost = numNewObjects + heap.extraCost;
-        if (newCost &gt;= ALLOCATIONS_PER_COLLECTION &amp;&amp; newCost &gt;= numLiveObjectsAtLastCollect)
-            goto collect;
-    }
</del><ins>+    // Fast case: find the next garbage cell and recycle it.
</ins><span class="cx"> 
</span><del>-    ASSERT(heap.operationInProgress == NoOperation);
-#ifndef NDEBUG
-    // FIXME: Consider doing this in NDEBUG builds too (see comment above).
-    heap.operationInProgress = Allocation;
-#endif
</del><ins>+    do {
+        ASSERT(heap.nextBlock &lt; heap.usedBlocks);
+        Block* block = reinterpret_cast&lt;Block*&gt;(heap.blocks[heap.nextBlock]);
+        do {
+            ASSERT(heap.nextCell &lt; HeapConstants&lt;heapType&gt;::cellsPerBlock);
+            if (!block-&gt;marked.get(heap.nextCell &gt;&gt; HeapConstants&lt;heapType&gt;::bitmapShift)) { // Always false for the last cell in the block
+                Cell* cell = block-&gt;cells + heap.nextCell;
+                if (heapType != NumberHeap) {
+                    heap.operationInProgress = Allocation;
+                    JSCell* imp = reinterpret_cast&lt;JSCell*&gt;(cell);
+                    imp-&gt;~JSCell();
+                    heap.operationInProgress = NoOperation;
+                }
+                ++heap.nextCell;
+                return cell;
+            }
+        } while (++heap.nextCell != HeapConstants&lt;heapType&gt;::cellsPerBlock);
+        heap.nextCell = 0;
+    } while (++heap.nextBlock != heap.usedBlocks);
</ins><span class="cx"> 
</span><del>-scan:
-    Block* targetBlock;
-    size_t targetBlockUsedCells;
-    if (i != usedBlocks) {
-        targetBlock = reinterpret_cast&lt;Block*&gt;(heap.blocks[i]);
-        targetBlockUsedCells = targetBlock-&gt;usedCells;
-        ASSERT(targetBlockUsedCells &lt;= HeapConstants&lt;heapType&gt;::cellsPerBlock);
-        while (targetBlockUsedCells == HeapConstants&lt;heapType&gt;::cellsPerBlock) {
-            if (++i == usedBlocks)
-                goto collect;
-            targetBlock = reinterpret_cast&lt;Block*&gt;(heap.blocks[i]);
-            targetBlockUsedCells = targetBlock-&gt;usedCells;
-            ASSERT(targetBlockUsedCells &lt;= HeapConstants&lt;heapType&gt;::cellsPerBlock);
-        }
-        heap.firstBlockWithPossibleSpace = i;
-    } else {
</del><ins>+    // Slow case: reached the end of the heap. Mark live objects and start over.
</ins><span class="cx"> 
</span><del>-collect:
-        size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
-        size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
-        const size_t newCost = numNewObjects + heap.extraCost;
</del><ins>+    reset();
+    goto allocate;
+}
</ins><span class="cx"> 
</span><del>-        if (newCost &gt;= ALLOCATIONS_PER_COLLECTION &amp;&amp; newCost &gt;= numLiveObjectsAtLastCollect) {
-#ifndef NDEBUG
-            heap.operationInProgress = NoOperation;
-#endif
-            bool foundGarbage = collect();
-            numLiveObjects = heap.numLiveObjects;
-            usedBlocks = heap.usedBlocks;
-            i = heap.firstBlockWithPossibleSpace;
-#ifndef NDEBUG
-            heap.operationInProgress = Allocation;
-#endif
-            if (foundGarbage)
-                goto scan;
-        }
</del><ins>+template &lt;HeapType heapType&gt;
+void Heap::resizeBlocks()
+{
+    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
</ins><span class="cx"> 
</span><del>-        // didn't find a block, and GC didn't reclaim anything, need to allocate a new block
-        targetBlock = reinterpret_cast&lt;Block*&gt;(allocateBlock&lt;heapType&gt;());
-        heap.firstBlockWithPossibleSpace = heap.usedBlocks - 1;
-        targetBlockUsedCells = 0;
-    }
</del><ins>+    heap.didShrink = false;
</ins><span class="cx"> 
</span><del>-    // find a free spot in the block and detach it from the free list
-    Cell* newCell = targetBlock-&gt;freeList;
</del><ins>+    size_t usedCellCount = markedCells&lt;heapType&gt;();
+    size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
+    size_t minBlockCount = (minCellCount + HeapConstants&lt;heapType&gt;::cellsPerBlock - 1) / HeapConstants&lt;heapType&gt;::cellsPerBlock;
</ins><span class="cx"> 
</span><del>-    // &quot;next&quot; field is a cell offset -- 0 means next cell, so a zeroed block is already initialized
-    targetBlock-&gt;freeList = (newCell + 1) + newCell-&gt;u.freeCell.next;
</del><ins>+    size_t maxCellCount = 1.25f * minCellCount;
+    size_t maxBlockCount = (maxCellCount + HeapConstants&lt;heapType&gt;::cellsPerBlock - 1) / HeapConstants&lt;heapType&gt;::cellsPerBlock;
</ins><span class="cx"> 
</span><del>-    targetBlock-&gt;usedCells = static_cast&lt;uint32_t&gt;(targetBlockUsedCells + 1);
-    heap.numLiveObjects = numLiveObjects + 1;
</del><ins>+    if (heap.usedBlocks &lt; minBlockCount)
+        growBlocks&lt;heapType&gt;(minBlockCount);
+    else if (heap.usedBlocks &gt; maxBlockCount)
+        shrinkBlocks&lt;heapType&gt;(maxBlockCount);
+}
</ins><span class="cx"> 
</span><del>-#ifndef NDEBUG
-    // FIXME: Consider doing this in NDEBUG builds too (see comment above).
-    heap.operationInProgress = NoOperation;
-#endif
</del><ins>+template &lt;HeapType heapType&gt; 
+void Heap::growBlocks(size_t neededBlocks)
+{
+    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+    ASSERT(heap.usedBlocks &lt; neededBlocks);
+    while (heap.usedBlocks &lt; neededBlocks)
+        allocateBlock&lt;heapType&gt;();
+}
</ins><span class="cx"> 
</span><del>-    return newCell;
</del><ins>+template &lt;HeapType heapType&gt; 
+void Heap::shrinkBlocks(size_t neededBlocks)
+{
+    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+    ASSERT(heap.usedBlocks &gt; neededBlocks);
+    
+    // Clear the always-on last bit, so isEmpty() isn't fooled by it.
+    for (size_t i = 0; i &lt; heap.usedBlocks; ++i)
+        heap.blocks[i]-&gt;marked.clear((HeapConstants&lt;heapType&gt;::cellsPerBlock - 1) &gt;&gt; HeapConstants&lt;heapType&gt;::bitmapShift);
+
+    for (size_t i = 0; i != heap.usedBlocks &amp;&amp; heap.usedBlocks != neededBlocks; ) {
+        if (heap.blocks[i]-&gt;marked.isEmpty()) {
+            freeBlock&lt;heapType&gt;(i);
+            heap.didShrink = true;
+        } else
+            ++i;
+    }
+
+    // Reset the always-on last bit.
+    for (size_t i = 0; i &lt; heap.usedBlocks; ++i)
+        heap.blocks[i]-&gt;marked.set((HeapConstants&lt;heapType&gt;::cellsPerBlock - 1) &gt;&gt; HeapConstants&lt;heapType&gt;::bitmapShift);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void* Heap::allocate(size_t s)
</span><span class="lines">@@ -714,11 +733,38 @@
</span><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) &amp; (sizeof(char*) - 1)) == 0)
</del><ins>+inline bool isPointerAligned(void* p)
+{
+    return (((intptr_t)(p) &amp; (sizeof(char*) - 1)) == 0);
+}
</ins><span class="cx"> 
</span><del>-// cell size needs to be a power of two for this to be valid
-#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) &amp; (CELL_MASK &gt;&gt; 1)) == 0)
</del><ins>+// Cell size needs to be a power of two for isPossibleCell to be valid.
+COMPILE_ASSERT(sizeof(CollectorCell) % 2 == 0, Collector_cell_size_is_power_of_two);
</ins><span class="cx"> 
</span><ins>+#if USE(JSVALUE32)
+static bool isHalfCellAligned(void *p)
+{
+    return (((intptr_t)(p) &amp; (CELL_MASK &gt;&gt; 1)) == 0);
+}
+
+static inline bool isPossibleCell(void* p)
+{
+    return isHalfCellAligned(p) &amp;&amp; p;
+}
+
+#else
+
+static inline bool isCellAligned(void *p)
+{
+    return (((intptr_t)(p) &amp; CELL_MASK) == 0);
+}
+
+static inline bool isPossibleCell(void* p)
+{
+    return isCellAligned(p) &amp;&amp; p;
+}
+#endif
+
</ins><span class="cx"> void Heap::markConservatively(MarkStack&amp; markStack, void* start, void* end)
</span><span class="cx"> {
</span><span class="cx">     if (start &gt; end) {
</span><span class="lines">@@ -728,47 +774,49 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT((static_cast&lt;char*&gt;(end) - static_cast&lt;char*&gt;(start)) &lt; 0x1000000);
</span><del>-    ASSERT(IS_POINTER_ALIGNED(start));
-    ASSERT(IS_POINTER_ALIGNED(end));
</del><ins>+    ASSERT(isPointerAligned(start));
+    ASSERT(isPointerAligned(end));
</ins><span class="cx"> 
</span><span class="cx">     char** p = static_cast&lt;char**&gt;(start);
</span><span class="cx">     char** e = static_cast&lt;char**&gt;(end);
</span><span class="cx"> 
</span><del>-    size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
-    size_t usedNumberBlocks = numberHeap.usedBlocks;
-    CollectorBlock** primaryBlocks = primaryHeap.blocks;
-    CollectorBlock** numberBlocks = numberHeap.blocks;
-
-    const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
-
</del><span class="cx">     while (p != e) {
</span><span class="cx">         char* x = *p++;
</span><del>-        if (IS_HALF_CELL_ALIGNED(x) &amp;&amp; x) {
</del><ins>+        if (isPossibleCell(x)) {
</ins><span class="cx">             uintptr_t xAsBits = reinterpret_cast&lt;uintptr_t&gt;(x);
</span><span class="cx">             xAsBits &amp;= CELL_ALIGN_MASK;
</span><span class="cx">             uintptr_t offset = xAsBits &amp; BLOCK_OFFSET_MASK;
</span><ins>+
+            const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
+            if (offset &gt; lastCellOffset)
+                continue;
+
</ins><span class="cx">             CollectorBlock* blockAddr = reinterpret_cast&lt;CollectorBlock*&gt;(xAsBits - offset);
</span><ins>+#if USE(JSVALUE32)
</ins><span class="cx">             // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost
</span><ins>+            size_t usedNumberBlocks = numberHeap.usedBlocks;
+            CollectorBlock** numberBlocks = numberHeap.blocks;
</ins><span class="cx">             for (size_t block = 0; block &lt; usedNumberBlocks; block++) {
</span><del>-                if ((numberBlocks[block] == blockAddr) &amp; (offset &lt;= lastCellOffset)) {
</del><ins>+                if (numberBlocks[block] == blockAddr) {
</ins><span class="cx">                     Heap::markCell(reinterpret_cast&lt;JSCell*&gt;(xAsBits));
</span><del>-                    goto endMarkLoop;
</del><ins>+                    goto loopEnd;
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><del>-          
</del><ins>+#endif
</ins><span class="cx">             // Mark the primary heap
</span><ins>+            size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
+            CollectorBlock** primaryBlocks = primaryHeap.blocks;
</ins><span class="cx">             for (size_t block = 0; block &lt; usedPrimaryBlocks; block++) {
</span><del>-                if ((primaryBlocks[block] == blockAddr) &amp; (offset &lt;= lastCellOffset)) {
-                    if (reinterpret_cast&lt;CollectorCell*&gt;(xAsBits)-&gt;u.freeCell.zeroIfFree) {
-                        markStack.append(reinterpret_cast&lt;JSCell*&gt;(xAsBits));
-                        markStack.drain();
-                    }
-                    break;
-                }
</del><ins>+                if (primaryBlocks[block] != blockAddr)
+                    continue;
+                markStack.append(reinterpret_cast&lt;JSCell*&gt;(xAsBits));
+                markStack.drain();
+                break;
</ins><span class="cx">             }
</span><del>-        endMarkLoop:
-            ;
</del><span class="cx">         }
</span><ins>+#if USE(JSVALUE32)
+loopEnd:
+#endif
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1009,129 +1057,78 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template &lt;HeapType heapType&gt; size_t Heap::sweep()
</del><ins>+template &lt;HeapType heapType&gt; 
+void Heap::clearMarkBits()
</ins><span class="cx"> {
</span><del>-    typedef typename HeapConstants&lt;heapType&gt;::Block Block;
-    typedef typename HeapConstants&lt;heapType&gt;::Cell Cell;
</del><ins>+    CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+    for (size_t i = 0; i &lt; heap.usedBlocks; ++i)
+        clearMarkBits&lt;heapType&gt;(heap.blocks[i]);
+}
</ins><span class="cx"> 
</span><del>-    // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
</del><ins>+template &lt;HeapType heapType&gt; 
+void Heap::clearMarkBits(CollectorBlock* block)
+{
+    // heapAllocate assumes that the last cell in every block is marked.
+    block-&gt;marked.clearAll();
+    block-&gt;marked.set((HeapConstants&lt;heapType&gt;::cellsPerBlock - 1) &gt;&gt; HeapConstants&lt;heapType&gt;::bitmapShift);
+}
+
+template &lt;HeapType heapType&gt; 
+size_t Heap::markedCells(size_t startBlock, size_t startCell) const
+{
+    const CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+    ASSERT(startBlock &lt;= heap.usedBlocks);
+    ASSERT(startCell &lt; HeapConstants&lt;heapType&gt;::cellsPerBlock);
+
+    if (startBlock &gt;= heap.usedBlocks)
+        return 0;
+
+    size_t result = 0;
+    result += heap.blocks[startBlock]-&gt;marked.count(startCell);
+    for (size_t i = startBlock + 1; i &lt; heap.usedBlocks; ++i)
+        result += heap.blocks[i]-&gt;marked.count();
+
+    return result;
+}
+
+template &lt;HeapType heapType&gt; 
+void Heap::sweep()
+{
+    ASSERT(heapType != NumberHeap); // The number heap does not contain meaningful destructors.
+
</ins><span class="cx">     CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
</span><ins>+
+    ASSERT(heap.operationInProgress == NoOperation);
+    if (heap.operationInProgress != NoOperation)
+        CRASH();
+    heap.operationInProgress = Collection;
</ins><span class="cx">     
</span><del>-    size_t emptyBlocks = 0;
-    size_t numLiveObjects = heap.numLiveObjects;
-    
-    for (size_t block = 0; block &lt; heap.usedBlocks; block++) {
-        Block* curBlock = reinterpret_cast&lt;Block*&gt;(heap.blocks[block]);
-        
-        size_t usedCells = curBlock-&gt;usedCells;
-        Cell* freeList = curBlock-&gt;freeList;
-        
-        if (usedCells == HeapConstants&lt;heapType&gt;::cellsPerBlock) {
-            // special case with a block where all cells are used -- testing indicates this happens often
-            for (size_t i = 0; i &lt; HeapConstants&lt;heapType&gt;::cellsPerBlock; i++) {
-                if (!curBlock-&gt;marked.get(i &gt;&gt; HeapConstants&lt;heapType&gt;::bitmapShift)) {
-                    Cell* cell = curBlock-&gt;cells + i;
-                    
-                    if (heapType != NumberHeap) {
-                        JSCell* imp = reinterpret_cast&lt;JSCell*&gt;(cell);
-                        // special case for allocated but uninitialized object
-                        // (We don't need this check earlier because nothing prior this point 
-                        // assumes the object has a valid vptr.)
-                        if (cell-&gt;u.freeCell.zeroIfFree == 0)
-                            continue;
-#if ENABLE(JSC_ZOMBIES)
-                        if (!imp-&gt;isZombie()) {
-                            const ClassInfo* info = imp-&gt;classInfo();
-                            imp-&gt;~JSCell();
-                            new (imp) JSZombie(info, JSZombie::leakedZombieStructure());
-                            heap.numZombies++;
-                        }
-#else
-                        imp-&gt;~JSCell();
-#endif
-                    }
-                    --numLiveObjects;
</del><span class="cx"> #if !ENABLE(JSC_ZOMBIES)
</span><del>-                    --usedCells;
-                    
-                    // put cell on the free list
-                    cell-&gt;u.freeCell.zeroIfFree = 0;
-                    cell-&gt;u.freeCell.next = freeList - (cell + 1);
-                    freeList = cell;
</del><ins>+    Structure* dummyMarkableCellStructure = m_globalData-&gt;dummyMarkableCellStructure.get();
</ins><span class="cx"> #endif
</span><del>-                }
-            }
-        } else {
-            size_t minimumCellsToProcess = usedCells;
-            for (size_t i = 0; (i &lt; minimumCellsToProcess) &amp; (i &lt; HeapConstants&lt;heapType&gt;::cellsPerBlock); i++) {
-                Cell* cell = curBlock-&gt;cells + i;
-                if (cell-&gt;u.freeCell.zeroIfFree == 0) {
-                    ++minimumCellsToProcess;
-                } else {
-                    if (!curBlock-&gt;marked.get(i &gt;&gt; HeapConstants&lt;heapType&gt;::bitmapShift)) {
-                        if (heapType != NumberHeap) {
-                            JSCell* imp = reinterpret_cast&lt;JSCell*&gt;(cell);
</del><ins>+
+    DeadObjectIterator&lt;heapType&gt; it(heap, heap.nextBlock, heap.nextCell);
+    DeadObjectIterator&lt;heapType&gt; end(heap, heap.usedBlocks);
+    for ( ; it != end; ++it) {
+        JSCell* cell = *it;
</ins><span class="cx"> #if ENABLE(JSC_ZOMBIES)
</span><del>-                            if (!imp-&gt;isZombie()) {
-                                const ClassInfo* info = imp-&gt;classInfo();
-                                imp-&gt;~JSCell();
-                                new (imp) JSZombie(info, JSZombie::leakedZombieStructure());
-                                heap.numZombies++;
-                            }
</del><ins>+        if (!cell-&gt;isZombie()) {
+            const ClassInfo* info = cell-&gt;classInfo();
+            cell-&gt;~JSCell();
+            new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
+            Heap::markCell(cell);
+        }
</ins><span class="cx"> #else
</span><del>-                            imp-&gt;~JSCell();
</del><ins>+        cell-&gt;~JSCell();
+        // Callers of sweep assume it's safe to mark any cell in the heap.
+        new (cell) JSCell(dummyMarkableCellStructure);
</ins><span class="cx"> #endif
</span><del>-                        }
-#if !ENABLE(JSC_ZOMBIES)
-                        --usedCells;
-                        --numLiveObjects;
-                        
-                        // put cell on the free list
-                        cell-&gt;u.freeCell.zeroIfFree = 0;
-                        cell-&gt;u.freeCell.next = freeList - (cell + 1); 
-                        freeList = cell;
-#endif
-                    }
-                }
-            }
-        }
-        
-        curBlock-&gt;usedCells = static_cast&lt;uint32_t&gt;(usedCells);
-        curBlock-&gt;freeList = freeList;
-        curBlock-&gt;marked.clearAll();
-        
-        if (!usedCells)
-            ++emptyBlocks;
</del><span class="cx">     }
</span><del>-    
-    if (heap.numLiveObjects != numLiveObjects)
-        heap.firstBlockWithPossibleSpace = 0;
-    
-    heap.numLiveObjects = numLiveObjects;
-    heap.numLiveObjectsAtLastCollect = numLiveObjects;
-    heap.extraCost = 0;
-    
-    if (!emptyBlocks)
-        return numLiveObjects;
</del><span class="cx"> 
</span><del>-    size_t neededCells = 1.25f * (numLiveObjects + max(ALLOCATIONS_PER_COLLECTION, numLiveObjects));
-    size_t neededBlocks = (neededCells + HeapConstants&lt;heapType&gt;::cellsPerBlock - 1) / HeapConstants&lt;heapType&gt;::cellsPerBlock;
-    for (size_t block = 0; block &lt; heap.usedBlocks; block++) {
-        if (heap.usedBlocks &lt;= neededBlocks)
-            break;
-
-        Block* curBlock = reinterpret_cast&lt;Block*&gt;(heap.blocks[block]);
-        if (curBlock-&gt;usedCells)
-            continue;
-
-        freeBlock&lt;heapType&gt;(block);
-        block--; // Don't move forward a step in this case
-    }
-
-    return numLiveObjects;
</del><ins>+    heap.operationInProgress = NoOperation;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool Heap::collect()
</del><ins>+void Heap::markRoots()
</ins><span class="cx"> {
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     if (m_globalData-&gt;isSharedInstance) {
</span><span class="lines">@@ -1140,23 +1137,31 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation));
-    if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation))
</del><ins>+    ASSERT((primaryHeap.operationInProgress == NoOperation) &amp; (numberHeap.operationInProgress == NoOperation));
+    if (!((primaryHeap.operationInProgress == NoOperation) &amp; (numberHeap.operationInProgress == NoOperation)))
</ins><span class="cx">         CRASH();
</span><span class="cx"> 
</span><del>-    JAVASCRIPTCORE_GC_BEGIN();
</del><span class="cx">     primaryHeap.operationInProgress = Collection;
</span><span class="cx">     numberHeap.operationInProgress = Collection;
</span><span class="cx"> 
</span><del>-    // MARK: first mark all referenced objects recursively starting out from the set of root objects
</del><span class="cx">     MarkStack&amp; markStack = m_globalData-&gt;markStack;
</span><ins>+
+    // Reset mark bits.
+    clearMarkBits&lt;PrimaryHeap&gt;();
+    clearMarkBits&lt;NumberHeap&gt;();
+
+    // Mark stack roots.
</ins><span class="cx">     markStackObjectsConservatively(markStack);
</span><ins>+    m_globalData-&gt;interpreter-&gt;registerFile().markCallFrames(markStack, this);
+
+    // Mark explicitly registered roots.
</ins><span class="cx">     markProtectedObjects(markStack);
</span><ins>+
+    // Mark misc. other roots.
</ins><span class="cx">     if (m_markListSet &amp;&amp; m_markListSet-&gt;size())
</span><span class="cx">         MarkedArgumentBuffer::markLists(markStack, *m_markListSet);
</span><span class="cx">     if (m_globalData-&gt;exception)
</span><span class="cx">         markStack.append(m_globalData-&gt;exception);
</span><del>-    m_globalData-&gt;interpreter-&gt;registerFile().markCallFrames(markStack, this);
</del><span class="cx">     m_globalData-&gt;smallStrings.markChildren(markStack);
</span><span class="cx">     if (m_globalData-&gt;functionCodeBlockBeingReparsed)
</span><span class="cx">         m_globalData-&gt;functionCodeBlockBeingReparsed-&gt;markAggregate(markStack);
</span><span class="lines">@@ -1165,41 +1170,41 @@
</span><span class="cx"> 
</span><span class="cx">     markStack.drain();
</span><span class="cx">     markStack.compact();
</span><del>-    JAVASCRIPTCORE_GC_MARKED();
</del><span class="cx"> 
</span><del>-    size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
-    size_t numLiveObjects = sweep&lt;PrimaryHeap&gt;();
-    numLiveObjects += sweep&lt;NumberHeap&gt;();
-
</del><span class="cx">     primaryHeap.operationInProgress = NoOperation;
</span><span class="cx">     numberHeap.operationInProgress = NoOperation;
</span><del>-    JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects);
</del><ins>+}
</ins><span class="cx"> 
</span><del>-    return numLiveObjects &lt; originalLiveObjects;
</del><ins>+size_t Heap::objectCount() const
+{
+    return objectCount&lt;PrimaryHeap&gt;() + objectCount&lt;NumberHeap&gt;();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-size_t Heap::objectCount() 
</del><ins>+template &lt;HeapType heapType&gt; 
+size_t Heap::objectCount() const
</ins><span class="cx"> {
</span><del>-    return primaryHeap.numLiveObjects + numberHeap.numLiveObjects - m_globalData-&gt;smallStrings.count(); 
</del><ins>+    const CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+
+    return heap.nextBlock * HeapConstants&lt;heapType&gt;::cellsPerBlock // allocated full blocks
+           + heap.nextCell // allocated cells in current block
+           + markedCells&lt;heapType&gt;(heap.nextBlock, heap.nextCell) // marked cells in remainder of heap
+           - heap.usedBlocks; // 1 cell per block is a dummy sentinel
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;HeapType heapType&gt; 
</span><del>-static void addToStatistics(Heap::Statistics&amp; statistics, const CollectorHeap&amp; heap)
</del><ins>+void Heap::addToStatistics(Heap::Statistics&amp; statistics) const
</ins><span class="cx"> {
</span><del>-    typedef HeapConstants&lt;heapType&gt; HC;
-    for (size_t i = 0; i &lt; heap.usedBlocks; ++i) {
-        if (heap.blocks[i]) {
-            statistics.size += BLOCK_SIZE;
-            statistics.free += (HC::cellsPerBlock - heap.blocks[i]-&gt;usedCells) * HC::cellSize;
-        }
-    }
</del><ins>+    const CollectorHeap&amp; heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+
+    statistics.size += heap.usedBlocks * BLOCK_SIZE;
+    statistics.free += heap.usedBlocks * BLOCK_SIZE - (objectCount&lt;heapType&gt;() * HeapConstants&lt;heapType&gt;::cellSize);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Heap::Statistics Heap::statistics() const
</span><span class="cx"> {
</span><span class="cx">     Statistics statistics = { 0, 0 };
</span><del>-    JSC::addToStatistics&lt;PrimaryHeap&gt;(statistics, primaryHeap);
-    JSC::addToStatistics&lt;NumberHeap&gt;(statistics, numberHeap);
</del><ins>+    addToStatistics&lt;PrimaryHeap&gt;(statistics);
+    addToStatistics&lt;NumberHeap&gt;(statistics);
</ins><span class="cx">     return statistics;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1271,14 +1276,68 @@
</span><span class="cx">     return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Heap::iterator Heap::primaryHeapBegin()
</del><ins>+void Heap::reset()
</ins><span class="cx"> {
</span><del>-    return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks);
</del><ins>+    JAVASCRIPTCORE_GC_BEGIN();
+
+    markRoots();
+
+    JAVASCRIPTCORE_GC_MARKED();
+
+    primaryHeap.nextCell = 0;
+    primaryHeap.nextBlock = 0;
+    primaryHeap.extraCost = 0;
+#if ENABLE(JSC_ZOMBIES)
+    sweep&lt;PrimaryHeap&gt;();
+#endif
+    resizeBlocks&lt;PrimaryHeap&gt;();
+
+#if USE(JSVALUE32)
+    numberHeap.nextCell = 0;
+    numberHeap.nextBlock = 0;
+    resizeBlocks&lt;NumberHeap&gt;();
+#endif
+
+    JAVASCRIPTCORE_GC_END();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-Heap::iterator Heap::primaryHeapEnd()
</del><ins>+void Heap::collectAllGarbage()
</ins><span class="cx"> {
</span><del>-    return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks);
</del><ins>+    JAVASCRIPTCORE_GC_BEGIN();
+
+    // If the last iteration through the heap deallocated blocks, we need
+    // to clean up remaining garbage before marking. Otherwise, the conservative
+    // marking mechanism might follow a pointer to unmapped memory.
+    if (primaryHeap.didShrink)
+        sweep&lt;PrimaryHeap&gt;();
+
+    markRoots();
+
+    JAVASCRIPTCORE_GC_MARKED();
+
+    primaryHeap.nextCell = 0;
+    primaryHeap.nextBlock = 0;
+    primaryHeap.extraCost = 0;
+    sweep&lt;PrimaryHeap&gt;();
+    resizeBlocks&lt;PrimaryHeap&gt;();
+
+#if USE(JSVALUE32)
+    numberHeap.nextCell = 0;
+    numberHeap.nextBlock = 0;
+    resizeBlocks&lt;NumberHeap&gt;();
+#endif
+
+    JAVASCRIPTCORE_GC_END();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+LiveObjectIterator&lt;PrimaryHeap&gt; Heap::primaryHeapBegin()
+{
+    return LiveObjectIterator&lt;PrimaryHeap&gt;(primaryHeap, 0);
+}
+
+LiveObjectIterator&lt;PrimaryHeap&gt; Heap::primaryHeapEnd()
+{
+    return LiveObjectIterator&lt;PrimaryHeap&gt;(primaryHeap, primaryHeap.usedBlocks);
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeCollectorh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/Collector.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/Collector.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/Collector.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -28,9 +28,9 @@
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> #include &lt;wtf/OwnPtr.h&gt;
</span><ins>+#include &lt;wtf/StdLibExtras.h&gt;
</ins><span class="cx"> #include &lt;wtf/Threading.h&gt;
</span><span class="cx"> 
</span><del>-// This is supremely lame that we require pthreads to build on windows.
</del><span class="cx"> #if ENABLE(JSC_MULTIPLE_THREADS)
</span><span class="cx"> #include &lt;pthread.h&gt;
</span><span class="cx"> #endif
</span><span class="lines">@@ -49,20 +49,19 @@
</span><span class="cx">     enum OperationInProgress { NoOperation, Allocation, Collection };
</span><span class="cx">     enum HeapType { PrimaryHeap, NumberHeap };
</span><span class="cx"> 
</span><del>-    template &lt;HeapType&gt; class CollectorHeapIterator;
</del><ins>+    template &lt;HeapType&gt; class LiveObjectIterator;
</ins><span class="cx"> 
</span><span class="cx">     struct CollectorHeap {
</span><ins>+        size_t nextBlock;
+        size_t nextCell;
+
</ins><span class="cx">         CollectorBlock** blocks;
</span><span class="cx">         size_t numBlocks;
</span><span class="cx">         size_t usedBlocks;
</span><del>-        size_t firstBlockWithPossibleSpace;
</del><span class="cx"> 
</span><del>-        size_t numLiveObjects;
-        size_t numLiveObjectsAtLastCollect;
</del><span class="cx">         size_t extraCost;
</span><del>-#if ENABLE(JSC_ZOMBIES)
-        size_t numZombies;
-#endif
</del><ins>+        
+        bool didShrink;
</ins><span class="cx"> 
</span><span class="cx">         OperationInProgress operationInProgress;
</span><span class="cx">     };
</span><span class="lines">@@ -70,21 +69,21 @@
</span><span class="cx">     class Heap : public Noncopyable {
</span><span class="cx">     public:
</span><span class="cx">         class Thread;
</span><del>-        typedef CollectorHeapIterator&lt;PrimaryHeap&gt; iterator;
</del><span class="cx"> 
</span><span class="cx">         void destroy();
</span><span class="cx"> 
</span><span class="cx">         void* allocateNumber(size_t);
</span><span class="cx">         void* allocate(size_t);
</span><span class="cx"> 
</span><del>-        bool collect();
</del><span class="cx">         bool isBusy(); // true if an allocation or collection is in progress
</span><ins>+        void collectAllGarbage();
</ins><span class="cx"> 
</span><del>-        static const size_t minExtraCostSize = 256;
</del><ins>+        static const size_t minExtraCost = 256;
+        static const size_t maxExtraCost = 1024 * 1024;
</ins><span class="cx"> 
</span><span class="cx">         void reportExtraMemoryCost(size_t cost);
</span><span class="cx"> 
</span><del>-        size_t objectCount();
</del><ins>+        size_t objectCount() const;
</ins><span class="cx">         struct Statistics {
</span><span class="cx">             size_t size;
</span><span class="cx">             size_t free;
</span><span class="lines">@@ -114,13 +113,14 @@
</span><span class="cx">         JSGlobalData* globalData() const { return m_globalData; }
</span><span class="cx">         static bool isNumber(JSCell*);
</span><span class="cx">         
</span><del>-        // Iterators for the object heap.
-        iterator primaryHeapBegin();
-        iterator primaryHeapEnd();
</del><ins>+        LiveObjectIterator&lt;PrimaryHeap&gt; primaryHeapBegin();
+        LiveObjectIterator&lt;PrimaryHeap&gt; primaryHeapEnd();
</ins><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         template &lt;HeapType heapType&gt; void* heapAllocate(size_t);
</span><del>-        template &lt;HeapType heapType&gt; size_t sweep();
</del><ins>+        void reset();
+        void collectRemainingGarbage();
+        template &lt;HeapType heapType&gt; void sweep();
</ins><span class="cx">         static CollectorBlock* cellBlock(const JSCell*);
</span><span class="cx">         static size_t cellOffset(const JSCell*);
</span><span class="cx"> 
</span><span class="lines">@@ -131,9 +131,20 @@
</span><span class="cx">         template &lt;HeapType heapType&gt; NEVER_INLINE CollectorBlock* allocateBlock();
</span><span class="cx">         template &lt;HeapType heapType&gt; NEVER_INLINE void freeBlock(size_t);
</span><span class="cx">         NEVER_INLINE void freeBlock(CollectorBlock*);
</span><del>-        void freeBlocks(CollectorHeap*);
</del><ins>+        template &lt;HeapType heapType&gt; void freeBlocks();
+        template &lt;HeapType heapType&gt; void resizeBlocks();
+        template &lt;HeapType heapType&gt; void growBlocks(size_t neededBlocks);
+        template &lt;HeapType heapType&gt; void shrinkBlocks(size_t neededBlocks);
+        template &lt;HeapType heapType&gt; void clearMarkBits();
+        template &lt;HeapType heapType&gt; void clearMarkBits(CollectorBlock*);
+        template &lt;HeapType heapType&gt; size_t markedCells(size_t startBlock = 0, size_t startCell = 0) const;
</ins><span class="cx"> 
</span><span class="cx">         void recordExtraCost(size_t);
</span><ins>+
+        template &lt;HeapType heapType&gt; void addToStatistics(Statistics&amp;) const;
+        template &lt;HeapType heapType&gt; size_t objectCount() const;
+
+        void markRoots();
</ins><span class="cx">         void markProtectedObjects(MarkStack&amp;);
</span><span class="cx">         void markCurrentThreadConservatively(MarkStack&amp;);
</span><span class="cx">         void markCurrentThreadConservativelyInternal(MarkStack&amp;);
</span><span class="lines">@@ -189,44 +200,49 @@
</span><span class="cx">     const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
</span><span class="cx">     const size_t CELL_MASK = CELL_SIZE - 1;
</span><span class="cx">     const size_t CELL_ALIGN_MASK = ~CELL_MASK;
</span><del>-    const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
</del><ins>+    const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*) - sizeof(HeapType)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells.
+    
</ins><span class="cx">     const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
</span><span class="cx">     const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
</span><span class="cx">     const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
</span><del>-  
</del><ins>+
</ins><span class="cx">     struct CollectorBitmap {
</span><span class="cx">         uint32_t bits[BITMAP_WORDS];
</span><span class="cx">         bool get(size_t n) const { return !!(bits[n &gt;&gt; 5] &amp; (1 &lt;&lt; (n &amp; 0x1F))); } 
</span><span class="cx">         void set(size_t n) { bits[n &gt;&gt; 5] |= (1 &lt;&lt; (n &amp; 0x1F)); } 
</span><span class="cx">         void clear(size_t n) { bits[n &gt;&gt; 5] &amp;= ~(1 &lt;&lt; (n &amp; 0x1F)); } 
</span><span class="cx">         void clearAll() { memset(bits, 0, sizeof(bits)); }
</span><ins>+        size_t count(size_t startCell = 0)
+        {
+            size_t result = 0;
+            for ( ; (startCell &amp; 0x1F) != 0; ++startCell) {
+                if (get(startCell))
+                    ++result;
+            }
+            for (size_t i = startCell &gt;&gt; 5; i &lt; BITMAP_WORDS; ++i)
+                result += WTF::bitCount(bits[i]);
+            return result;
+        }
+        size_t isEmpty() // Much more efficient than testing count() == 0.
+        {
+            for (size_t i = 0; i &lt; BITMAP_WORDS; ++i)
+                if (bits[i] != 0)
+                    return false;
+            return true;
+        }
</ins><span class="cx">     };
</span><span class="cx">   
</span><span class="cx">     struct CollectorCell {
</span><del>-        union {
-            double memory[CELL_ARRAY_LENGTH];
-            struct {
-                void* zeroIfFree;
-                ptrdiff_t next;
-            } freeCell;
-        } u;
</del><ins>+        double memory[CELL_ARRAY_LENGTH];
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct SmallCollectorCell {
</span><del>-        union {
-            double memory[CELL_ARRAY_LENGTH / 2];
-            struct {
-                void* zeroIfFree;
-                ptrdiff_t next;
-            } freeCell;
-        } u;
</del><ins>+        double memory[CELL_ARRAY_LENGTH / 2];
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     class CollectorBlock {
</span><span class="cx">     public:
</span><span class="cx">         CollectorCell cells[CELLS_PER_BLOCK];
</span><del>-        uint32_t usedCells;
-        CollectorCell* freeList;
</del><span class="cx">         CollectorBitmap marked;
</span><span class="cx">         Heap* heap;
</span><span class="cx">         HeapType type;
</span><span class="lines">@@ -235,8 +251,6 @@
</span><span class="cx">     class SmallCellCollectorBlock {
</span><span class="cx">     public:
</span><span class="cx">         SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
</span><del>-        uint32_t usedCells;
-        SmallCollectorCell* freeList;
</del><span class="cx">         CollectorBitmap marked;
</span><span class="cx">         Heap* heap;
</span><span class="cx">         HeapType type;
</span><span class="lines">@@ -287,8 +301,8 @@
</span><span class="cx"> 
</span><span class="cx">     inline void Heap::reportExtraMemoryCost(size_t cost)
</span><span class="cx">     {
</span><del>-        if (cost &gt; minExtraCostSize) 
-            recordExtraCost(cost / (CELL_SIZE * 2)); 
</del><ins>+        if (cost &gt; minExtraCost) 
+            recordExtraCost(cost);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeCollectorHeapIteratorh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/CollectorHeapIterator.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/CollectorHeapIterator.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/CollectorHeapIterator.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -31,60 +31,119 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-    template &lt;HeapType heapType&gt; class CollectorHeapIterator {
</del><ins>+    class CollectorHeapIterator {
</ins><span class="cx">     public:
</span><del>-        CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock);
-
-        bool operator!=(const CollectorHeapIterator&lt;heapType&gt;&amp; other) { return m_block != other.m_block || m_cell != other.m_cell; }
-        CollectorHeapIterator&lt;heapType&gt;&amp; operator++();
</del><ins>+        bool operator!=(const CollectorHeapIterator&amp; other);
</ins><span class="cx">         JSCell* operator*() const;
</span><span class="cx">     
</span><del>-    private:
-        typedef typename HeapConstants&lt;heapType&gt;::Block Block;
-        typedef typename HeapConstants&lt;heapType&gt;::Cell Cell;
</del><ins>+    protected:
+        CollectorHeapIterator(CollectorHeap&amp;, size_t startBlock, size_t startCell);
+        void advance(size_t cellsPerBlock);
</ins><span class="cx"> 
</span><del>-        Block** m_block;
-        Block** m_endBlock;
-        Cell* m_cell;
-        Cell* m_endCell;
</del><ins>+        CollectorHeap&amp; m_heap;
+        size_t m_block;
+        size_t m_cell;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><del>-    template &lt;HeapType heapType&gt; 
-    CollectorHeapIterator&lt;heapType&gt;::CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock)
-        : m_block(reinterpret_cast&lt;Block**&gt;(block))
-        , m_endBlock(reinterpret_cast&lt;Block**&gt;(endBlock))
-        , m_cell(m_block == m_endBlock ? 0 : (*m_block)-&gt;cells)
-        , m_endCell(m_block == m_endBlock ? 0 : (*m_block)-&gt;cells + HeapConstants&lt;heapType&gt;::cellsPerBlock)
</del><ins>+    template &lt;HeapType heapType&gt;
+    class LiveObjectIterator : public CollectorHeapIterator {
+    public:
+        LiveObjectIterator(CollectorHeap&amp;, size_t startBlock, size_t startCell = 0);
+        LiveObjectIterator&lt;heapType&gt;&amp; operator++();
+    };
+
+    template &lt;HeapType heapType&gt;
+    class DeadObjectIterator : public CollectorHeapIterator {
+    public:
+        DeadObjectIterator(CollectorHeap&amp;, size_t startBlock, size_t startCell = 0);
+        DeadObjectIterator&lt;heapType&gt;&amp; operator++();
+    };
+
+    template &lt;HeapType heapType&gt;
+    class ObjectIterator : public CollectorHeapIterator {
+    public:
+        ObjectIterator(CollectorHeap&amp;, size_t startBlock, size_t startCell = 0);
+        ObjectIterator&lt;heapType&gt;&amp; operator++();
+    };
+
+    inline CollectorHeapIterator::CollectorHeapIterator(CollectorHeap&amp; heap, size_t startBlock, size_t startCell)
+        : m_heap(heap)
+        , m_block(startBlock)
+        , m_cell(startCell)
</ins><span class="cx">     {
</span><del>-        if (m_cell &amp;&amp; m_cell-&gt;u.freeCell.zeroIfFree == 0)
-            ++*this;
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template &lt;HeapType heapType&gt; 
-    CollectorHeapIterator&lt;heapType&gt;&amp; CollectorHeapIterator&lt;heapType&gt;::operator++()
</del><ins>+    inline bool CollectorHeapIterator::operator!=(const CollectorHeapIterator&amp; other)
</ins><span class="cx">     {
</span><ins>+        return m_block != other.m_block || m_cell != other.m_cell;
+    }
+
+    inline JSCell* CollectorHeapIterator::operator*() const
+    {
+        return reinterpret_cast&lt;JSCell*&gt;(m_heap.blocks[m_block]-&gt;cells + m_cell);
+    }
+    
+    inline void CollectorHeapIterator::advance(size_t cellsPerBlock)
+    {
+        ++m_cell;
+        if (m_cell == cellsPerBlock) {
+            m_cell = 0;
+            ++m_block;
+        }
+    }
+
+    template &lt;HeapType heapType&gt;
+    inline LiveObjectIterator&lt;heapType&gt;::LiveObjectIterator(CollectorHeap&amp; heap, size_t startBlock, size_t startCell)
+        : CollectorHeapIterator(heap, startBlock, startCell - 1)
+    {
+        ++(*this);
+    }
+
+    template &lt;HeapType heapType&gt;
+    inline LiveObjectIterator&lt;heapType&gt;&amp; LiveObjectIterator&lt;heapType&gt;::operator++()
+    {
+        if (m_block &lt; m_heap.nextBlock || m_cell &lt; m_heap.nextCell) {
+            advance(HeapConstants&lt;heapType&gt;::cellsPerBlock);
+            return *this;
+        }
+
</ins><span class="cx">         do {
</span><del>-            for (++m_cell; m_cell != m_endCell; ++m_cell)
-                if (m_cell-&gt;u.freeCell.zeroIfFree != 0) {
-                    return *this;
-                }
</del><ins>+            advance(HeapConstants&lt;heapType&gt;::cellsPerBlock);
+        } while (m_block &lt; m_heap.usedBlocks &amp;&amp; !m_heap.blocks[m_block]-&gt;marked.get(m_cell));
+        return *this;
+    }
</ins><span class="cx"> 
</span><del>-            if (++m_block != m_endBlock) {
-                m_cell = (*m_block)-&gt;cells;
-                m_endCell = (*m_block)-&gt;cells + HeapConstants&lt;heapType&gt;::cellsPerBlock;
-            }
-        } while(m_block != m_endBlock);
</del><ins>+    template &lt;HeapType heapType&gt;
+    inline DeadObjectIterator&lt;heapType&gt;::DeadObjectIterator(CollectorHeap&amp; heap, size_t startBlock, size_t startCell)
+        : CollectorHeapIterator(heap, startBlock, startCell - 1)
+    {
+        ++(*this);
+    }
</ins><span class="cx"> 
</span><del>-        m_cell = 0;
</del><ins>+    template &lt;HeapType heapType&gt;
+    inline DeadObjectIterator&lt;heapType&gt;&amp; DeadObjectIterator&lt;heapType&gt;::operator++()
+    {
+        do {
+            advance(HeapConstants&lt;heapType&gt;::cellsPerBlock);
+            ASSERT(m_block &gt; m_heap.nextBlock || (m_block == m_heap.nextBlock &amp;&amp; m_cell &gt;= m_heap.nextCell));
+        } while (m_block &lt; m_heap.usedBlocks &amp;&amp; m_heap.blocks[m_block]-&gt;marked.get(m_cell));
</ins><span class="cx">         return *this;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template &lt;HeapType heapType&gt; 
-    JSCell* CollectorHeapIterator&lt;heapType&gt;::operator*() const
</del><ins>+    template &lt;HeapType heapType&gt;
+    inline ObjectIterator&lt;heapType&gt;::ObjectIterator(CollectorHeap&amp; heap, size_t startBlock, size_t startCell)
+        : CollectorHeapIterator(heap, startBlock, startCell - 1)
</ins><span class="cx">     {
</span><del>-        return reinterpret_cast&lt;JSCell*&gt;(m_cell);
</del><ins>+        ++(*this);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    template &lt;HeapType heapType&gt;
+    inline ObjectIterator&lt;heapType&gt;&amp; ObjectIterator&lt;heapType&gt;::operator++()
+    {
+        advance(HeapConstants&lt;heapType&gt;::cellsPerBlock);
+        return *this;
+    }
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // CollectorHeapIterator_h
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSArraycpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSArray.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSArray.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/JSArray.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -380,8 +380,6 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned vectorLength = m_vectorLength;
</span><span class="cx"> 
</span><del>-    Heap::heap(this)-&gt;reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
-
</del><span class="cx">     if (newNumValuesInVector == storage-&gt;m_numValuesInVector + 1) {
</span><span class="cx">         for (unsigned j = vectorLength; j &lt; newVectorLength; ++j)
</span><span class="cx">             storage-&gt;m_vector[j] = JSValue();
</span><span class="lines">@@ -402,6 +400,8 @@
</span><span class="cx">     m_storage = storage;
</span><span class="cx"> 
</span><span class="cx">     checkConsistency();
</span><ins>+
+    Heap::heap(this)-&gt;reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool JSArray::deleteProperty(ExecState* exec, const Identifier&amp; propertyName)
</span><span class="lines">@@ -492,13 +492,15 @@
</span><span class="cx">     if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    Heap::heap(this)-&gt;reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
</del><span class="cx">     m_vectorLength = newVectorLength;
</span><span class="cx"> 
</span><span class="cx">     for (unsigned i = vectorLength; i &lt; newVectorLength; ++i)
</span><span class="cx">         storage-&gt;m_vector[i] = JSValue();
</span><span class="cx"> 
</span><span class="cx">     m_storage = storage;
</span><ins>+
+    Heap::heap(this)-&gt;reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
+
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSCellh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSCell.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSCell.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/JSCell.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -47,10 +47,18 @@
</span><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         explicit JSCell(Structure*);
</span><del>-        JSCell(); // Only used for initializing Collector blocks.
</del><ins>+        
+        // Only used for initializing Collector blocks.
+        enum DummyDestructableCellTag { DummyDestructableCell };
+        JSCell(DummyDestructableCellTag);
</ins><span class="cx">         virtual ~JSCell();
</span><span class="cx"> 
</span><span class="cx">     public:
</span><ins>+        static PassRefPtr&lt;Structure&gt; createDummyStructure()
+        {
+            return Structure::create(jsNull(), TypeInfo(UnspecifiedType));
+        }
+
</ins><span class="cx">         // Querying the type.
</span><span class="cx"> #if USE(JSVALUE32)
</span><span class="cx">         bool isNumber() const;
</span><span class="lines">@@ -122,8 +130,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Only used for initializing Collector blocks.
-    inline JSCell::JSCell()
</del><ins>+    inline JSCell::JSCell(DummyDestructableCellTag)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSGlobalDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSGlobalData.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSGlobalData.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/JSGlobalData.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -126,6 +126,7 @@
</span><span class="cx">     , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
</span><span class="cx">     , getterSetterStructure(GetterSetter::createStructure(jsNull()))
</span><span class="cx">     , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
</span><ins>+    , dummyMarkableCellStructure(JSCell::createDummyStructure())
</ins><span class="cx"> #if USE(JSVALUE32)
</span><span class="cx">     , numberStructure(JSNumberCell::createStructure(jsNull()))
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSGlobalDatah"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSGlobalData.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSGlobalData.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/JSGlobalData.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -123,6 +123,7 @@
</span><span class="cx">         RefPtr&lt;Structure&gt; propertyNameIteratorStructure;
</span><span class="cx">         RefPtr&lt;Structure&gt; getterSetterStructure;
</span><span class="cx">         RefPtr&lt;Structure&gt; apiWrapperStructure;
</span><ins>+        RefPtr&lt;Structure&gt; dummyMarkableCellStructure;
</ins><span class="cx"> 
</span><span class="cx"> #if USE(JSVALUE32)
</span><span class="cx">         RefPtr&lt;Structure&gt; numberStructure;
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeJSStringh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/JSString.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/JSString.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/JSString.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -421,7 +421,7 @@
</span><span class="cx">             if (c &lt;= 0xFF)
</span><span class="cx">                 return globalData-&gt;smallStrings.singleCharacterString(globalData, c);
</span><span class="cx">         }
</span><del>-        return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)));
</del><ins>+        return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     inline JSString* jsOwnedString(JSGlobalData* globalData, const UString&amp; s)
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeTracingd"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/Tracing.d (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/Tracing.d        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/Tracing.d        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> {
</span><span class="cx">     probe gc__begin();
</span><span class="cx">     probe gc__marked();
</span><del>-    probe gc__end(int, int);
</del><ins>+    probe gc__end();
</ins><span class="cx">     
</span><span class="cx">     probe profile__will_execute(int, char*, char*, int);
</span><span class="cx">     probe profile__did_execute(int, char*, char*, int);
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeTracingh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/Tracing.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/Tracing.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/Tracing.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> #define JAVASCRIPTCORE_GC_BEGIN()
</span><span class="cx"> #define JAVASCRIPTCORE_GC_BEGIN_ENABLED() 0
</span><span class="cx"> 
</span><del>-#define JAVASCRIPTCORE_GC_END(arg0, arg1)
</del><ins>+#define JAVASCRIPTCORE_GC_END()
</ins><span class="cx"> #define JAVASCRIPTCORE_GC_END_ENABLED() 0
</span><span class="cx"> 
</span><span class="cx"> #define JAVASCRIPTCORE_GC_MARKED()
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeUStringh"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/runtime/UString.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/UString.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/runtime/UString.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -512,7 +512,7 @@
</span><span class="cx">     // huge buffer.
</span><span class="cx">     // FIXME: this should be size_t but that would cause warnings until we
</span><span class="cx">     // fix UString sizes to be size_t instead of int
</span><del>-    static const int minShareSize = Heap::minExtraCostSize / sizeof(UChar);
</del><ins>+    static const int minShareSize = Heap::minExtraCost / sizeof(UChar);
</ins><span class="cx"> 
</span><span class="cx">     inline size_t UString::cost() const
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkJavaScriptCoreruntimeWeakGCMaph"></a>
<div class="addfile"><h4>Added: trunk/JavaScriptCore/runtime/WeakGCMap.h (0 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/runtime/WeakGCMap.h                                (rev 0)
+++ trunk/JavaScriptCore/runtime/WeakGCMap.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -0,0 +1,234 @@
</span><ins>+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WeakGCMap_h
+#define WeakGCMap_h
+
+#include &lt;wtf/HashMap.h&gt;
+
+namespace JSC {
+
+class JSCell;
+
+// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
+template&lt;typename KeyType, typename MappedType&gt;
+class WeakGCMap {
+    /*
+    Invariants:
+        * A value enters the WeakGCMap marked. (Guaranteed by set()).
+        * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
+        * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
+        * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
+    */
+
+public:
+    typedef typename HashMap&lt;KeyType, MappedType&gt;::iterator iterator;
+    typedef typename HashMap&lt;KeyType, MappedType&gt;::const_iterator const_iterator;
+    
+    bool isEmpty() { return m_map.isEmpty(); }
+
+    MappedType get(const KeyType&amp; key) const;
+    pair&lt;iterator, bool&gt; set(const KeyType&amp;, const MappedType&amp;); 
+    MappedType take(const KeyType&amp; key);
+
+    // These unchecked functions provide access to a value even if the value's
+    // mark bit is not set. This is used, among other things, to retrieve values
+    // during the GC mark phase, which begins by clearing all mark bits.
+
+    MappedType uncheckedGet(const KeyType&amp; key) const { return m_map.get(key); }
+    bool uncheckedRemove(const KeyType&amp;, const MappedType&amp;);
+
+    iterator uncheckedBegin() { return m_map.begin(); }
+    iterator uncheckedEnd() { return m_map.end(); }
+
+    const_iterator uncheckedBegin() const { return m_map.begin(); }
+    const_iterator uncheckedEnd() const { return m_map.end(); }
+
+private:
+    HashMap&lt;KeyType, MappedType&gt; m_map;
+};
+
+template&lt;typename KeyType, typename MappedType&gt;
+MappedType WeakGCMap&lt;KeyType, MappedType&gt;::get(const KeyType&amp; key) const
+{
+    MappedType result = m_map.get(key);
+    if (!Heap::isCellMarked(result))
+        return HashTraits&lt;MappedType&gt;::emptyValue();
+    return result;
+}
+
+template&lt;typename KeyType, typename MappedType&gt;
+MappedType WeakGCMap&lt;KeyType, MappedType&gt;::take(const KeyType&amp; key)
+{
+    MappedType result = m_map.take(key);
+    if (!Heap::isCellMarked(result))
+        return HashTraits&lt;MappedType&gt;::emptyValue();
+    return result;
+}
+
+template&lt;typename KeyType, typename MappedType&gt;
+pair&lt;typename HashMap&lt;KeyType, MappedType&gt;::iterator, bool&gt; WeakGCMap&lt;KeyType, MappedType&gt;::set(const KeyType&amp; key, const MappedType&amp; value)
+{
+    Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now.
+    pair&lt;iterator, bool&gt; result = m_map.add(key, value);
+    if (!result.second) { // pre-existing entry
+        result.second = !Heap::isCellMarked(result.first-&gt;second);
+        result.first-&gt;second = value;
+    }
+    return result;
+}
+
+template&lt;typename KeyType, typename MappedType&gt;
+bool WeakGCMap&lt;KeyType, MappedType&gt;::uncheckedRemove(const KeyType&amp; key, const MappedType&amp; value)
+{
+    iterator it = m_map.find(key);
+    if (it == m_map.end())
+        return false;
+    if (it-&gt;second != value)
+        return false;
+    m_map.remove(it);
+    return true;
+}
+
+} // namespace JSC
+
+#endif // WeakGCMap_h
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WeakGCMap_h
+#define WeakGCMap_h
+
+#include &lt;wtf/HashMap.h&gt;
+
+namespace JSC {
+
+class JSCell;
+
+// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
+template&lt;typename KeyType, typename MappedType&gt;
+class WeakGCMap {
+    /*
+    Invariants:
+        * A value enters the WeakGCMap marked. (Guaranteed by set()).
+        * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
+        * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
+        * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
+    */
+
+public:
+    typedef typename HashMap&lt;KeyType, MappedType&gt;::iterator iterator;
+    typedef typename HashMap&lt;KeyType, MappedType&gt;::const_iterator const_iterator;
+    
+    bool isEmpty() { return m_map.isEmpty(); }
+
+    MappedType get(const KeyType&amp; key) const;
+    pair&lt;iterator, bool&gt; set(const KeyType&amp;, const MappedType&amp;); 
+    MappedType take(const KeyType&amp; key);
+
+    // These unchecked functions provide access to a value even if the value's
+    // mark bit is not set. This is used, among other things, to retrieve values
+    // during the GC mark phase, which begins by clearing all mark bits.
+
+    MappedType uncheckedGet(const KeyType&amp; key) const { return m_map.get(key); }
+    bool uncheckedRemove(const KeyType&amp;, const MappedType&amp;);
+
+    iterator uncheckedBegin() { return m_map.begin(); }
+    iterator uncheckedEnd() { return m_map.end(); }
+
+    const_iterator uncheckedBegin() const { return m_map.begin(); }
+    const_iterator uncheckedEnd() const { return m_map.end(); }
+
+private:
+    HashMap&lt;KeyType, MappedType&gt; m_map;
+};
+
+template&lt;typename KeyType, typename MappedType&gt;
+MappedType WeakGCMap&lt;KeyType, MappedType&gt;::get(const KeyType&amp; key) const
+{
+    MappedType result = m_map.get(key);
+    if (!Heap::isCellMarked(result))
+        return HashTraits&lt;MappedType&gt;::emptyValue();
+    return result;
+}
+
+template&lt;typename KeyType, typename MappedType&gt;
+MappedType WeakGCMap&lt;KeyType, MappedType&gt;::take(const KeyType&amp; key)
+{
+    MappedType result = m_map.take(key);
+    if (!Heap::isCellMarked(result))
+        return HashTraits&lt;MappedType&gt;::emptyValue();
+    return result;
+}
+
+template&lt;typename KeyType, typename MappedType&gt;
+pair&lt;typename HashMap&lt;KeyType, MappedType&gt;::iterator, bool&gt; WeakGCMap&lt;KeyType, MappedType&gt;::set(const KeyType&amp; key, const MappedType&amp; value)
+{
+    Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now.
+    pair&lt;iterator, bool&gt; result = m_map.add(key, value);
+    if (!result.second) { // pre-existing entry
+        result.second = !Heap::isCellMarked(result.first-&gt;second);
+        result.first-&gt;second = value;
+    }
+    return result;
+}
+
+template&lt;typename KeyType, typename MappedType&gt;
+bool WeakGCMap&lt;KeyType, MappedType&gt;::uncheckedRemove(const KeyType&amp; key, const MappedType&amp; value)
+{
+    iterator it = m_map.find(key);
+    if (it == m_map.end())
+        return false;
+    if (it-&gt;second != value)
+        return false;
+    m_map.remove(it);
+    return true;
+}
+
+} // namespace JSC
+
+#endif // WeakGCMap_h
</ins></span></pre></div>
<a id="trunkJavaScriptCorewtfStdLibExtrash"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptCore/wtf/StdLibExtras.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptCore/wtf/StdLibExtras.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptCore/wtf/StdLibExtras.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -69,6 +69,14 @@
</span><span class="cx">         return u.to;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Returns a count of the number of bits set in 'bits'.
+    inline size_t bitCount(uint32_t bits)
+    {
+        bits = bits - ((bits &gt;&gt; 1) &amp; 0x55555555);
+        bits = (bits &amp; 0x33333333) + ((bits &gt;&gt; 2) &amp; 0x33333333);
+        return ((bits + (bits &gt;&gt; 4) &amp; 0xF0F0F0F) * 0x1010101) &gt;&gt; 24;
+    }
+
</ins><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkJavaScriptGlueChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptGlue/ChangeLog (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptGlue/ChangeLog        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptGlue/ChangeLog        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2009-12-11  Geoffrey Garen  &lt;ggaren@apple.com&gt;
+
+        Reviewed by Sam Weinig.
+        
+        Changed GC from mark-sweep to mark-allocate.
+        
+        * JavaScriptGlue.cpp:
+        (JSCollect): Updated for rename. Fixed a bug where JSGlue would not check
+        to avoid nested GC calls.
+
</ins><span class="cx"> 2009-12-08  Dmitry Titov  &lt;dimich@chromium.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Rubber-stamped by David Levin.
</span></span></pre></div>
<a id="trunkJavaScriptGlueJavaScriptGluecpp"></a>
<div class="modfile"><h4>Modified: trunk/JavaScriptGlue/JavaScriptGlue.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JavaScriptGlue/JavaScriptGlue.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/JavaScriptGlue/JavaScriptGlue.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -339,7 +339,9 @@
</span><span class="cx">     initializeThreading();
</span><span class="cx"> 
</span><span class="cx">     JSLock lock(LockForReal);
</span><del>-    getThreadGlobalExecState()-&gt;heap()-&gt;collect();
</del><ins>+    Heap* heap = getThreadGlobalExecState()-&gt;heap();
+    if (!heap-&gt;isBusy())
+        heap-&gt;collectAllGarbage();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /*
</span></span></pre></div>
<a id="trunkWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/ChangeLog (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/ChangeLog        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/ChangeLog        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -1,3 +1,59 @@
</span><ins>+2009-12-11  Geoffrey Garen  &lt;ggaren@apple.com&gt;
+
+        Reviewed by Sam Weinig.
+        
+        Changed GC from mark-sweep to mark-allocate.
+
+        * ForwardingHeaders/runtime/WeakGCMap.h: Added.
+        * bindings/js/GCController.cpp:
+        (WebCore::collect):
+        (WebCore::GCController::gcTimerFired):
+        (WebCore::GCController::garbageCollectNow): Updated for rename.
+
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::removeWrappers):
+        (WebCore::hasCachedDOMObjectWrapperUnchecked):
+        (WebCore::hasCachedDOMObjectWrapper):
+        (WebCore::hasCachedDOMNodeWrapperUnchecked):
+        (WebCore::forgetDOMObject):
+        (WebCore::forgetDOMNode):
+        (WebCore::isObservableThroughDOM):
+        (WebCore::markDOMNodesForDocument):
+        (WebCore::markDOMObjectWrapper):
+        (WebCore::markDOMNodeWrapper):
+        * bindings/js/JSDOMBinding.h: Changed DOM wrapper maps to be WeakGCMaps.
+        Don't ASSERT that an item must be in the WeakGCMap when its destructor
+        runs, since it might have been overwritten in the map first.
+
+        * bindings/js/JSDocumentCustom.cpp:
+        (WebCore::toJS): Changed Document from a DOM object wrapper to a DOM node
+        wrapper, to simplify some code.
+
+        * bindings/js/JSInspectedObjectWrapper.cpp:
+        (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
+        (WebCore::JSInspectedObjectWrapper::~JSInspectedObjectWrapper):
+        * bindings/js/JSInspectorCallbackWrapper.cpp: Use a WeakGCMap for these
+        wrappers.
+
+        * bindings/js/JSNodeCustom.cpp:
+        (WebCore::JSNode::markChildren): Updated for WeakGCMap and Document using
+        a DOM node wrapper instead of a DOM object wrapper.
+
+        * bindings/js/JSSVGPODTypeWrapper.h:
+        (WebCore::JSSVGDynamicPODTypeWrapperCache::wrapperMap):
+        (WebCore::JSSVGDynamicPODTypeWrapperCache::lookupOrCreateWrapper):
+        (WebCore::JSSVGDynamicPODTypeWrapperCache::forgetWrapper):
+        (WebCore::::~JSSVGDynamicPODTypeWrapper): Shined a small beam of sanity
+        on this code. Use hashtable-based lookup in JSSVGPODTypeWrapper.h instead
+        of linear lookup through iteration, since that's what hashtables were
+        invented for. Make JSSVGPODTypeWrapper.h responsible for reomving itself
+        from the table, instead of its JS wrapper, to decouple these objects from
+        GC, and because these objects are refCounted, not solely owned by their
+        JS wrappers.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        * dom/Document.h: Adopted changes above.
+
</ins><span class="cx"> 2009-12-11  Dimitri Glazkov  &lt;dglazkov@chromium.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, build fix.
</span></span></pre></div>
<a id="trunkWebCoreForwardingHeadersruntimeWeakGCMaph"></a>
<div class="addfile"><h4>Added: trunk/WebCore/ForwardingHeaders/runtime/WeakGCMap.h (0 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/ForwardingHeaders/runtime/WeakGCMap.h                                (rev 0)
+++ trunk/WebCore/ForwardingHeaders/runtime/WeakGCMap.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+#ifndef WebCore_FWD_WeakGCMap_h
+#define WebCore_FWD_WeakGCMap_h
+#include &lt;JavaScriptCore/WeakGCMap.h&gt;
+#endif
</ins></span></pre></div>
<a id="trunkWebCorebindingsjsGCControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/GCController.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/GCController.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/GCController.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> static void* collect(void*)
</span><span class="cx"> {
</span><span class="cx">     JSLock lock(SilenceAssertionsOnly);
</span><del>-    JSDOMWindow::commonJSGlobalData()-&gt;heap.collect();
</del><ins>+    JSDOMWindow::commonJSGlobalData()-&gt;heap.collectAllGarbage();
</ins><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -70,14 +70,12 @@
</span><span class="cx"> 
</span><span class="cx"> void GCController::gcTimerFired(Timer&lt;GCController&gt;*)
</span><span class="cx"> {
</span><del>-    JSLock lock(SilenceAssertionsOnly);
-    JSDOMWindow::commonJSGlobalData()-&gt;heap.collect();
</del><ins>+    collect(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void GCController::garbageCollectNow()
</span><span class="cx"> {
</span><del>-    JSLock lock(SilenceAssertionsOnly);
-    JSDOMWindow::commonJSGlobalData()-&gt;heap.collect();
</del><ins>+    collect(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void GCController::garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone)
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSDOMBindingcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSDOMBinding.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSDOMBinding.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSDOMBinding.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -134,15 +134,15 @@
</span><span class="cx"> 
</span><span class="cx"> static void removeWrappers(const JSWrapperCache&amp; wrappers)
</span><span class="cx"> {
</span><del>-    JSWrapperCache::const_iterator wrappersEnd = wrappers.end();
-    for (JSWrapperCache::const_iterator it = wrappers.begin(); it != wrappersEnd; ++it)
</del><ins>+    JSWrapperCache::const_iterator wrappersEnd = wrappers.uncheckedEnd();
+    for (JSWrapperCache::const_iterator it = wrappers.uncheckedBegin(); it != wrappersEnd; ++it)
</ins><span class="cx">         removeWrapper(it-&gt;second);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static inline void removeWrappers(const DOMObjectWrapperMap&amp; wrappers)
</span><span class="cx"> {
</span><del>-    DOMObjectWrapperMap::const_iterator wrappersEnd = wrappers.end();
-    for (DOMObjectWrapperMap::const_iterator it = wrappers.begin(); it != wrappersEnd; ++it)
</del><ins>+    DOMObjectWrapperMap::const_iterator wrappersEnd = wrappers.uncheckedEnd();
+    for (DOMObjectWrapperMap::const_iterator it = wrappers.uncheckedBegin(); it != wrappersEnd; ++it)
</ins><span class="cx">         removeWrapper(it-&gt;second);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -242,10 +242,19 @@
</span><span class="cx">     return currentWorld(exec)-&gt;m_wrappers;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool hasCachedDOMObjectWrapperUnchecked(JSGlobalData* globalData, void* objectHandle)
+{
+    for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
+        if (worldIter-&gt;m_wrappers.uncheckedGet(objectHandle))
+            return true;
+    }
+    return false;
+}
+
</ins><span class="cx"> bool hasCachedDOMObjectWrapper(JSGlobalData* globalData, void* objectHandle)
</span><span class="cx"> {
</span><span class="cx">     for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
</span><del>-        if (worldIter-&gt;m_wrappers.contains(objectHandle))
</del><ins>+        if (worldIter-&gt;m_wrappers.get(objectHandle))
</ins><span class="cx">             return true;
</span><span class="cx">     }
</span><span class="cx">     return false;
</span><span class="lines">@@ -262,14 +271,14 @@
</span><span class="cx">     DOMObjectWrapperMapFor(exec).set(objectHandle, wrapper);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool hasCachedDOMNodeWrapper(Document* document, Node* node)
</del><ins>+bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node)
</ins><span class="cx"> {
</span><span class="cx">     if (!document)
</span><del>-        return hasCachedDOMObjectWrapper(JSDOMWindow::commonJSGlobalData(), node);
</del><ins>+        return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node);
</ins><span class="cx"> 
</span><span class="cx">     JSWrapperCacheMap&amp; wrapperCacheMap = document-&gt;wrapperCacheMap();
</span><span class="cx">     for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
</span><del>-        if (iter-&gt;second-&gt;contains(node))
</del><ins>+        if (iter-&gt;second-&gt;uncheckedGet(node))
</ins><span class="cx">             return true;
</span><span class="cx">     }
</span><span class="cx">     return false;
</span><span class="lines">@@ -286,20 +295,13 @@
</span><span class="cx"> {
</span><span class="cx">     JSC::JSGlobalData* globalData = Heap::heap(wrapper)-&gt;globalData();
</span><span class="cx">     for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
</span><del>-        DOMObjectWrapperMap&amp; wrappers = worldIter-&gt;m_wrappers;
-        DOMObjectWrapperMap::iterator iter = wrappers.find(objectHandle);
-        if ((iter != wrappers.end()) &amp;&amp; (iter-&gt;second == wrapper)) {
-            removeWrapper(wrapper);
-            wrappers.remove(iter);
-            return;
-        }
</del><ins>+        if (worldIter-&gt;m_wrappers.uncheckedRemove(objectHandle, wrapper))
+            break;
</ins><span class="cx">     }
</span><del>-
-    // If the world went away, it should have removed this wrapper from the set.
-    ASSERT(!wrapperSet().contains(wrapper));
</del><ins>+    removeWrapper(wrapper);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void forgetDOMNode(DOMObject* wrapper, Node* node, Document* document)
</del><ins>+void forgetDOMNode(JSNode* wrapper, Node* node, Document* document)
</ins><span class="cx"> {
</span><span class="cx">     if (!document) {
</span><span class="cx">         forgetDOMObject(wrapper, node);
</span><span class="lines">@@ -308,17 +310,10 @@
</span><span class="cx"> 
</span><span class="cx">     JSWrapperCacheMap&amp; wrapperCacheMap = document-&gt;wrapperCacheMap();
</span><span class="cx">     for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
</span><del>-        JSWrapperCache* wrappers = wrappersIter-&gt;second;
-        JSWrapperCache::iterator iter = wrappers-&gt;find(node);
-        if ((iter != wrappers-&gt;end()) &amp;&amp; (iter-&gt;second == wrapper)) {
-            wrappers-&gt;remove(iter);
-            removeWrapper(wrapper);
-            return;
-        }
</del><ins>+        if (wrappersIter-&gt;second-&gt;uncheckedRemove(node, wrapper))
+            break;
</ins><span class="cx">     }
</span><del>-
-    // If the world went away, it should have removed this wrapper from the set.
-    ASSERT(!wrapperSet().contains(wrapper));
</del><ins>+    removeWrapper(wrapper);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper)
</span><span class="lines">@@ -379,14 +374,14 @@
</span><span class="cx">         // the custom markChildren functions rather than here.
</span><span class="cx">         if (node-&gt;isElementNode()) {
</span><span class="cx">             if (NamedNodeMap* attributes = static_cast&lt;Element*&gt;(node)-&gt;attributeMap()) {
</span><del>-                if (DOMObject* wrapper = world-&gt;m_wrappers.get(attributes)) {
</del><ins>+                if (DOMObject* wrapper = world-&gt;m_wrappers.uncheckedGet(attributes)) {
</ins><span class="cx">                     if (wrapper-&gt;hasCustomProperties())
</span><span class="cx">                         return true;
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">             if (node-&gt;isStyledElement()) {
</span><span class="cx">                 if (CSSMutableStyleDeclaration* style = static_cast&lt;StyledElement*&gt;(node)-&gt;inlineStyleDecl()) {
</span><del>-                    if (DOMObject* wrapper = world-&gt;m_wrappers.get(style)) {
</del><ins>+                    if (DOMObject* wrapper = world-&gt;m_wrappers.uncheckedGet(style)) {
</ins><span class="cx">                         if (wrapper-&gt;hasCustomProperties())
</span><span class="cx">                             return true;
</span><span class="cx">                     }
</span><span class="lines">@@ -394,7 +389,7 @@
</span><span class="cx">             }
</span><span class="cx">             if (static_cast&lt;Element*&gt;(node)-&gt;hasTagName(canvasTag)) {
</span><span class="cx">                 if (CanvasRenderingContext* context = static_cast&lt;HTMLCanvasElement*&gt;(node)-&gt;renderingContext()) {
</span><del>-                    if (DOMObject* wrapper = world-&gt;m_wrappers.get(context)) {
</del><ins>+                    if (DOMObject* wrapper = world-&gt;m_wrappers.uncheckedGet(context)) {
</ins><span class="cx">                         if (wrapper-&gt;hasCustomProperties())
</span><span class="cx">                             return true;
</span><span class="cx">                     }
</span><span class="lines">@@ -432,8 +427,8 @@
</span><span class="cx">         DOMWrapperWorld* world = wrappersIter-&gt;first;
</span><span class="cx">         JSWrapperCache* nodeDict = wrappersIter-&gt;second;
</span><span class="cx"> 
</span><del>-        JSWrapperCache::iterator nodeEnd = nodeDict-&gt;end();
-        for (JSWrapperCache::iterator nodeIt = nodeDict-&gt;begin(); nodeIt != nodeEnd; ++nodeIt) {
</del><ins>+        JSWrapperCache::iterator nodeEnd = nodeDict-&gt;uncheckedEnd();
+        for (JSWrapperCache::iterator nodeIt = nodeDict-&gt;uncheckedBegin(); nodeIt != nodeEnd; ++nodeIt) {
</ins><span class="cx">             JSNode* jsNode = nodeIt-&gt;second;
</span><span class="cx">             if (isObservableThroughDOM(jsNode, world))
</span><span class="cx">                 markStack.append(jsNode);
</span><span class="lines">@@ -516,7 +511,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     for (JSGlobalDataWorldIterator worldIter(&amp;globalData); worldIter; ++worldIter) {
</span><del>-        if (DOMObject* wrapper = worldIter-&gt;m_wrappers.get(object))
</del><ins>+        if (DOMObject* wrapper = worldIter-&gt;m_wrappers.uncheckedGet(object))
</ins><span class="cx">             markStack.append(wrapper);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -526,14 +521,14 @@
</span><span class="cx">     if (document) {
</span><span class="cx">         JSWrapperCacheMap&amp; wrapperCacheMap = document-&gt;wrapperCacheMap();
</span><span class="cx">         for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
</span><del>-            if (JSNode* wrapper = iter-&gt;second-&gt;get(node))
</del><ins>+            if (JSNode* wrapper = iter-&gt;second-&gt;uncheckedGet(node))
</ins><span class="cx">                 markStack.append(wrapper);
</span><span class="cx">         }
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
</span><del>-        if (DOMObject* wrapper = worldIter-&gt;m_wrappers.get(node))
</del><ins>+        if (DOMObject* wrapper = worldIter-&gt;m_wrappers.uncheckedGet(node))
</ins><span class="cx">             markStack.append(wrapper);
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSDOMBindingh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSDOMBinding.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSDOMBinding.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSDOMBinding.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -23,9 +23,10 @@
</span><span class="cx"> #define JSDOMBinding_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;JSDOMGlobalObject.h&quot;
</span><del>-#include &quot;Document.h&quot; // For DOMConstructorWithDocument
</del><ins>+#include &quot;Document.h&quot;
</ins><span class="cx"> #include &lt;runtime/Completion.h&gt;
</span><span class="cx"> #include &lt;runtime/Lookup.h&gt;
</span><ins>+#include &lt;runtime/WeakGCMap.h&gt;
</ins><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -139,7 +140,7 @@
</span><span class="cx">         }
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    typedef HashMap&lt;void*, DOMObject*&gt; DOMObjectWrapperMap;
</del><ins>+    typedef JSC::WeakGCMap&lt;void*, DOMObject*&gt; DOMObjectWrapperMap;
</ins><span class="cx"> 
</span><span class="cx">     class DOMWrapperWorld : public RefCounted&lt;DOMWrapperWorld&gt; {
</span><span class="cx">     public:
</span><span class="lines">@@ -216,22 +217,24 @@
</span><span class="cx">         DOMWrapperWorld m_normalWorld;
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    DOMObject* getCachedDOMObjectWrapper(JSC::ExecState*, void* objectHandle);
</ins><span class="cx">     bool hasCachedDOMObjectWrapper(JSC::JSGlobalData*, void* objectHandle);
</span><del>-    DOMObject* getCachedDOMObjectWrapper(JSC::ExecState*, void* objectHandle);
</del><span class="cx">     void cacheDOMObjectWrapper(JSC::ExecState*, void* objectHandle, DOMObject* wrapper);
</span><del>-    void forgetDOMNode(DOMObject* wrapper, Node* node, Document* document);
</del><ins>+    void forgetDOMNode(JSNode* wrapper, Node* node, Document* document);
</ins><span class="cx">     void forgetDOMObject(DOMObject* wrapper, void* objectHandle);
</span><span class="cx"> 
</span><del>-    bool hasCachedDOMNodeWrapper(Document*, Node*);
</del><span class="cx">     JSNode* getCachedDOMNodeWrapper(JSC::ExecState*, Document*, Node*);
</span><span class="cx">     void cacheDOMNodeWrapper(JSC::ExecState*, Document*, Node*, JSNode* wrapper);
</span><span class="cx">     void forgetAllDOMNodesForDocument(Document*);
</span><span class="cx">     void forgetWorldOfDOMNodesForDocument(Document*, DOMWrapperWorld*);
</span><span class="cx">     void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument);
</span><ins>+
</ins><span class="cx">     void markDOMNodesForDocument(JSC::MarkStack&amp;, Document*);
</span><span class="cx">     void markActiveObjectsForContext(JSC::MarkStack&amp;, JSC::JSGlobalData&amp;, ScriptExecutionContext*);
</span><span class="cx">     void markDOMObjectWrapper(JSC::MarkStack&amp;, JSC::JSGlobalData&amp; globalData, void* object);
</span><span class="cx">     void markDOMNodeWrapper(JSC::MarkStack&amp; markStack, Document* document, Node* node);
</span><ins>+    bool hasCachedDOMObjectWrapperUnchecked(JSC::JSGlobalData*, void* objectHandle);
+    bool hasCachedDOMNodeWrapperUnchecked(Document*, Node*);
</ins><span class="cx"> 
</span><span class="cx">     JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
</span><span class="cx">     JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, NonNullPassRefPtr&lt;JSC::Structure&gt;, const JSC::ClassInfo*);
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSDocumentCustomcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSDocumentCustom.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSDocumentCustom.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSDocumentCustom.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -96,18 +96,18 @@
</span><span class="cx">     if (!document)
</span><span class="cx">         return jsNull();
</span><span class="cx"> 
</span><del>-    DOMObject* wrapper = getCachedDOMObjectWrapper(exec, document);
</del><ins>+    DOMObject* wrapper = getCachedDOMNodeWrapper(exec, document, document);
</ins><span class="cx">     if (wrapper)
</span><span class="cx">         return wrapper;
</span><span class="cx"> 
</span><span class="cx">     if (document-&gt;isHTMLDocument())
</span><del>-        wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, HTMLDocument, document);
</del><ins>+        wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, HTMLDocument, document);
</ins><span class="cx"> #if ENABLE(SVG)
</span><span class="cx">     else if (document-&gt;isSVGDocument())
</span><del>-        wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, SVGDocument, document);
</del><ins>+        wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, SVGDocument, document);
</ins><span class="cx"> #endif
</span><span class="cx">     else
</span><del>-        wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, Document, document);
</del><ins>+        wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Document, document);
</ins><span class="cx"> 
</span><span class="cx">     // Make sure the document is kept around by the window object, and works right with the
</span><span class="cx">     // back/forward cache.
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSInspectedObjectWrappercpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSInspectedObjectWrapper.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSInspectedObjectWrapper.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSInspectedObjectWrapper.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;JSInspectorCallbackWrapper.h&quot;
</span><span class="cx"> #include &lt;runtime/JSGlobalObject.h&gt;
</span><ins>+#include &lt;runtime/WeakGCMap.h&gt;
</ins><span class="cx"> #include &lt;wtf/StdLibExtras.h&gt;
</span><span class="cx"> 
</span><span class="cx"> using namespace JSC;
</span><span class="lines">@@ -38,7 +39,7 @@
</span><span class="cx"> 
</span><span class="cx"> ASSERT_CLASS_FITS_IN_CELL(JSInspectedObjectWrapper);
</span><span class="cx"> 
</span><del>-typedef HashMap&lt;JSObject*, JSInspectedObjectWrapper*&gt; WrapperMap;
</del><ins>+typedef WeakGCMap&lt;JSObject*, JSInspectedObjectWrapper*&gt; WrapperMap;
</ins><span class="cx"> typedef HashMap&lt;JSGlobalObject*, WrapperMap*&gt; GlobalObjectWrapperMap;
</span><span class="cx"> 
</span><span class="cx"> static GlobalObjectWrapperMap&amp; wrappers()
</span><span class="lines">@@ -81,17 +82,17 @@
</span><span class="cx">         wrappers().set(unwrappedGlobalObject(), wrapperMap);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ASSERT(!wrapperMap-&gt;contains(unwrappedObject));
-    wrapperMap-&gt;set(unwrappedObject, this);
</del><ins>+    pair&lt;WrapperMap::iterator, bool&gt; result = wrapperMap-&gt;set(unwrappedObject, this);
+    ASSERT(result.second);
+    UNUSED_PARAM(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSInspectedObjectWrapper::~JSInspectedObjectWrapper()
</span><span class="cx"> {
</span><del>-    ASSERT(wrappers().contains(unwrappedGlobalObject()));
</del><span class="cx">     WrapperMap* wrapperMap = wrappers().get(unwrappedGlobalObject());
</span><ins>+    ASSERT(wrapperMap);
</ins><span class="cx"> 
</span><del>-    ASSERT(wrapperMap-&gt;contains(unwrappedObject()));
-    wrapperMap-&gt;remove(unwrappedObject());
</del><ins>+    wrapperMap-&gt;uncheckedRemove(unwrappedObject(), this);
</ins><span class="cx"> 
</span><span class="cx">     if (wrapperMap-&gt;isEmpty()) {
</span><span class="cx">         wrappers().remove(unwrappedGlobalObject());
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSInspectorCallbackWrappercpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSInspectorCallbackWrapper.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(INSPECTOR)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;JSInspectedObjectWrapper.h&quot;
</span><ins>+#include &lt;runtime/Protect.h&gt;
</ins><span class="cx"> #include &lt;wtf/StdLibExtras.h&gt;
</span><span class="cx"> 
</span><span class="cx"> using namespace JSC;
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSNodeCustomcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSNodeCustom.cpp (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSNodeCustom.cpp        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSNodeCustom.cpp        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -144,7 +144,7 @@
</span><span class="cx">     // mark any other nodes.
</span><span class="cx">     if (node-&gt;inDocument()) {
</span><span class="cx">         if (Document* doc = node-&gt;ownerDocument())
</span><del>-            markDOMObjectWrapper(markStack, *Heap::heap(this)-&gt;globalData(), doc);
</del><ins>+            markDOMNodeWrapper(markStack, doc, doc);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -154,7 +154,7 @@
</span><span class="cx">     Node* outermostNodeWithWrapper = node;
</span><span class="cx">     for (Node* current = m_impl.get(); current; current = current-&gt;parentNode()) {
</span><span class="cx">         root = current;
</span><del>-        if (hasCachedDOMNodeWrapper(current-&gt;document(), current))
</del><ins>+        if (hasCachedDOMNodeWrapperUnchecked(current-&gt;document(), current))
</ins><span class="cx">             outermostNodeWithWrapper = current;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebCorebindingsjsJSSVGPODTypeWrapperh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/js/JSSVGPODTypeWrapper.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/js/JSSVGPODTypeWrapper.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/js/JSSVGPODTypeWrapper.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -105,6 +105,8 @@
</span><span class="cx">         ASSERT(m_setter);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    virtual ~JSSVGDynamicPODTypeWrapper();
+
</ins><span class="cx">     // Update callbacks
</span><span class="cx">     RefPtr&lt;PODTypeCreator&gt; m_creator;
</span><span class="cx">     GetterMethod m_getter;
</span><span class="lines">@@ -351,6 +353,7 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+// Used for dynamic read-write attributes
</ins><span class="cx"> template&lt;typename PODType, typename PODTypeCreator&gt;
</span><span class="cx"> class JSSVGDynamicPODTypeWrapperCache {
</span><span class="cx"> public:
</span><span class="lines">@@ -362,49 +365,41 @@
</span><span class="cx">     typedef PODTypeWrapperCacheInfoTraits&lt;PODType, PODTypeCreator&gt; CacheInfoTraits;
</span><span class="cx"> 
</span><span class="cx">     typedef JSSVGPODTypeWrapper&lt;PODType&gt; WrapperBase;
</span><del>-    typedef JSSVGDynamicPODTypeWrapper&lt;PODType, PODTypeCreator&gt; DynamicWrapper;
-    typedef HashMap&lt;CacheInfo, DynamicWrapper*, CacheInfoHash, CacheInfoTraits&gt; DynamicWrapperHashMap;
-    typedef typename DynamicWrapperHashMap::const_iterator DynamicWrapperHashMapIterator;
</del><ins>+    typedef JSSVGDynamicPODTypeWrapper&lt;PODType, PODTypeCreator&gt; Wrapper;
+    typedef HashMap&lt;CacheInfo, Wrapper*, CacheInfoHash, CacheInfoTraits&gt; WrapperMap;
</ins><span class="cx"> 
</span><del>-    static DynamicWrapperHashMap&amp; dynamicWrapperHashMap()
</del><ins>+    static WrapperMap&amp; wrapperMap()
</ins><span class="cx">     {
</span><del>-        DEFINE_STATIC_LOCAL(DynamicWrapperHashMap, s_dynamicWrapperHashMap, ());
-        return s_dynamicWrapperHashMap;
</del><ins>+        DEFINE_STATIC_LOCAL(WrapperMap, s_wrapperMap, ());
+        return s_wrapperMap;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Used for readwrite attributes only
</del><span class="cx">     static PassRefPtr&lt;WrapperBase&gt; lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
</span><span class="cx">     {
</span><del>-        DynamicWrapperHashMap&amp; map(dynamicWrapperHashMap());
</del><span class="cx">         CacheInfo info(creator, getter, setter);
</span><ins>+        pair&lt;typename WrapperMap::iterator, bool&gt; result = wrapperMap().add(info, 0);
+        if (!result.second) // pre-existing entry
+            return result.first-&gt;second;
</ins><span class="cx"> 
</span><del>-        if (map.contains(info))
-            return map.get(info);
-
-        RefPtr&lt;DynamicWrapper&gt; wrapper = DynamicWrapper::create(creator, getter, setter);
-        map.set(info, wrapper.get());
</del><ins>+        RefPtr&lt;Wrapper&gt; wrapper = Wrapper::create(creator, getter, setter);
+        result.first-&gt;second = wrapper.get();
</ins><span class="cx">         return wrapper.release();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static void forgetWrapper(WrapperBase* wrapper)
</del><ins>+    static void forgetWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
</ins><span class="cx">     {
</span><del>-        DynamicWrapperHashMap&amp; map(dynamicWrapperHashMap());
-
-        DynamicWrapperHashMapIterator it = map.begin();
-        DynamicWrapperHashMapIterator end = map.end();
-
-        for (; it != end; ++it) {
-            if (it-&gt;second != wrapper)
-                continue;
-
-            // It's guaranteed that there's just one object we need to take care of.
-            map.remove(it-&gt;first);
-            break;
-        }
</del><ins>+        CacheInfo info(creator, getter, setter);
+        wrapperMap().remove(info);
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-};
</del><ins>+template&lt;typename PODType, typename PODTypeCreator&gt;
+JSSVGDynamicPODTypeWrapper&lt;PODType, PODTypeCreator&gt;::~JSSVGDynamicPODTypeWrapper()
+{
+    JSSVGDynamicPODTypeWrapperCache&lt;PODType, PODTypeCreator&gt;::forgetWrapper(m_creator.get(), m_getter, m_setter);
+}
</ins><span class="cx"> 
</span><ins>+} // namespace WebCore
+
</ins><span class="cx"> #endif // ENABLE(SVG)
</span><span class="cx"> #endif // JSSVGPODTypeWrapper_h
</span></span></pre></div>
<a id="trunkWebCorebindingsscriptsCodeGeneratorJSpm"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/bindings/scripts/CodeGeneratorJS.pm (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/bindings/scripts/CodeGeneratorJS.pm        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/bindings/scripts/CodeGeneratorJS.pm        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -566,7 +566,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Destructor
</span><del>-    push(@headerContent, &quot;    virtual ~$className();\n&quot;) if (!$hasParent or $eventTarget or $interfaceName eq &quot;Document&quot; or $interfaceName eq &quot;DOMWindow&quot;);
</del><ins>+    push(@headerContent, &quot;    virtual ~$className();\n&quot;) if (!$hasParent or $eventTarget or $interfaceName eq &quot;DOMWindow&quot;);
</ins><span class="cx"> 
</span><span class="cx">     # Prototype
</span><span class="cx">     push(@headerContent, &quot;    static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n&quot;) unless ($dataNode-&gt;extendedAttributes-&gt;{&quot;ExtendsDOMGlobalObject&quot;});
</span><span class="lines">@@ -1210,15 +1210,6 @@
</span><span class="cx">             if ($interfaceName eq &quot;Node&quot;) {
</span><span class="cx">                  push(@implContent, &quot;    forgetDOMNode(this, impl(), impl()-&gt;document());\n&quot;);
</span><span class="cx">             } else {
</span><del>-                if ($podType) {
-                    my $animatedType = $implClassName;
-                    $animatedType =~ s/SVG/SVGAnimated/;
-
-                    # Special case for JSSVGNumber
-                    if ($codeGenerator-&gt;IsSVGAnimatedType($animatedType) and $podType ne &quot;float&quot;) {
-                        push(@implContent, &quot;    JSSVGDynamicPODTypeWrapperCache&lt;$podType, $animatedType&gt;::forgetWrapper(m_impl.get());\n&quot;);
-                    }
-                }
</del><span class="cx">                 push(@implContent, &quot;    forgetDOMObject(this, impl());\n&quot;);
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -1226,13 +1217,6 @@
</span><span class="cx">         push(@implContent, &quot;}\n\n&quot;);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Document needs a special destructor because it's a special case for caching. It needs
-    # its own special handling rather than relying on the caching that Node normally does.
-    if ($interfaceName eq &quot;Document&quot;) {
-        push(@implContent, &quot;${className}::~$className()\n&quot;);
-        push(@implContent, &quot;{\n    forgetDOMObject(this, static_cast&lt;${implClassName}*&gt;(impl()));\n}\n\n&quot;);
-    }
-
</del><span class="cx">     if ($needsMarkChildren &amp;&amp; !$dataNode-&gt;extendedAttributes-&gt;{&quot;CustomMarkFunction&quot;}) {
</span><span class="cx">         push(@implContent, &quot;void ${className}::markChildren(MarkStack&amp; markStack)\n&quot;);
</span><span class="cx">         push(@implContent, &quot;{\n&quot;);
</span></span></pre></div>
<a id="trunkWebCoredomDocumenth"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/dom/Document.h (52039 => 52040)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/dom/Document.h        2009-12-12 04:56:51 UTC (rev 52039)
+++ trunk/WebCore/dom/Document.h        2009-12-12 05:29:56 UTC (rev 52040)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;DocumentMarker.h&quot;
</span><span class="cx"> #include &quot;ScriptExecutionContext.h&quot;
</span><span class="cx"> #include &quot;Timer.h&quot;
</span><ins>+#include &lt;runtime/WeakGCMap.h&gt;
</ins><span class="cx"> #include &lt;wtf/HashCountedSet.h&gt;
</span><span class="cx"> #include &lt;wtf/OwnPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/PassOwnPtr.h&gt;
</span><span class="lines">@@ -829,7 +830,7 @@
</span><span class="cx">     virtual void scriptImported(unsigned long, const String&amp;);
</span><span class="cx">     virtual void postTask(PassOwnPtr&lt;Task&gt;); // Executes the task on context's thread asynchronously.
</span><span class="cx"> 
</span><del>-    typedef HashMap&lt;WebCore::Node*, JSNode*&gt; JSWrapperCache;
</del><ins>+    typedef JSC::WeakGCMap&lt;WebCore::Node*, JSNode*&gt; JSWrapperCache;
</ins><span class="cx">     typedef HashMap&lt;DOMWrapperWorld*, JSWrapperCache*&gt; JSWrapperCacheMap;
</span><span class="cx">     JSWrapperCacheMap&amp; wrapperCacheMap() { return m_wrapperCacheMap; }
</span><span class="cx">     JSWrapperCache* getWrapperCache(DOMWrapperWorld* world)
</span></span></pre>
</div>
</div>

</body>
</html>