First step toward incremental Weak<T> finalization
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Apr 2012 05:28:13 +0000 (05:28 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Apr 2012 05:28:13 +0000 (05:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=82670

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch implements a Weak<T> heap that is compatible with incremental
finalization, while making as few behavior changes as possible. The behavior
changes it makes are:

(*) Weak<T>'s raw JSValue no longer reverts to JSValue() automatically --
instead, a separate flag indicates that the JSValue is no longer valid.
(This is required so that the JSValue can be preserved for later finalization.)
Objects dealing with WeakImpls directly must change to check the flag.

(*) Weak<T> is no longer a subclass of Handle<T>.

(*) DOM GC performance is different -- 9% faster in the geometric mean,
but 15% slower in one specific case:
        gc-dom1.html: 6%  faster
        gc-dom2.html: 23% faster
        gc-dom3.html: 17% faster
        gc-dom4.html: 15% *slower*

The key features of this new heap are:

(*) Each block knows its own state, independent of any other blocks.

(*) Each block caches its own sweep result.

(*) The heap visits dead Weak<T>s at the end of GC. (It doesn't
mark them yet, since that would be a behavior change.)

* API/JSCallbackObject.cpp:
(JSC::JSCallbackObjectData::finalize):
* API/JSCallbackObjectFunctions.h:
(JSC::::init): Updated to use the new WeakHeap API.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.gypi:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri: Paid the build system tax since I added some new files.

* heap/Handle.h: Made WeakBlock a friend and exposed slot() as public,
so we can keep passing a Handle<T> to finalizers, to avoid more surface
area change in this patch. A follow-up patch should change the type we
pass to finalizers.

* heap/HandleHeap.cpp:
(JSC):
(JSC::HandleHeap::writeBarrier):
(JSC::HandleHeap::isLiveNode):
* heap/HandleHeap.h:
(JSC):
(HandleHeap):
(Node):
(JSC::HandleHeap::Node::Node): Removed all code related to Weak<T>, since
we have a separate WeakHeap now.

* heap/Heap.cpp:
(JSC::Heap::Heap): Removed m_extraCost because extra cost is accounted
for through our watermark now. Removed m_waterMark because it was unused.

(JSC::Heap::destroy): Updated for addition of WeakHeap.

(JSC::Heap::reportExtraMemoryCostSlowCase): Changed from using its own
variable to participating in the watermark strategy. I wanted to standardize
WeakHeap and all other Heap clients on this strategy, to make sure it's
accurate.

(JSC::Heap::markRoots): Updated for addition of WeakHeap. Added WeakHeap
dead visit pass, as explained above.

(JSC::Heap::collect):
(JSC::Heap::resetAllocators): Updated for addition of WeakHeap.

(JSC::Heap::addFinalizer):
(JSC::Heap::FinalizerOwner::finalize): Updated for new Weak<T> API.

* heap/Heap.h:
(JSC::Heap::weakHeap):
(Heap):
(JSC::Heap::addToWaterMark): Added a way to participate in the watermarking
strategy, since this is the best way for WeakHeap to report its memory
cost. (I plan to update this in a follow-up patch to make it more accurate,
but for now it is not less accurate than it used to be.)

* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::MarkedSpace):
(JSC::MarkedSpace::resetAllocators):
* heap/MarkedSpace.h:
(MarkedSpace):
(JSC::MarkedSpace::addToWaterMark):
(JSC::MarkedSpace::didConsumeFreeList): Removed m_nurseryWaterMark because
it was unused, and I didn't want to update WeakHeap to keep an usused
variable working. Added API for above.

* heap/PassWeak.h:
(JSC):
(WeakImplAccessor):
(PassWeak):
(JSC::::operator):
(JSC::::get):
(JSC::::was):
(JSC::::PassWeak):
(JSC::::~PassWeak):
(JSC::UnspecifiedBoolType):
(JSC::::leakImpl):
(JSC::adoptWeak):
* heap/Strong.h:
(JSC::Strong::operator!):
(Strong):
(JSC::Strong::operator UnspecifiedBoolType*):
(JSC::Strong::get):
* heap/Weak.h:
(Weak):
(JSC::::Weak):
(JSC):
(JSC::::isHashTableDeletedValue):
(JSC::::~Weak):
(JSC::::swap):
(JSC::=):
(JSC::::operator):
(JSC::UnspecifiedBoolType):
(JSC::::release):
(JSC::::clear):
(JSC::::hashTableDeletedValue): Lots of code changes here, but they boil
down to two things:

(*) Allocate WeakImpls from the WeakHeap instead of Handles from the HandleHeap.

(*) Explicitly check WeakImpl::state() for non-liveness before returning
a value (explained above).

These files implement the new Weak<T> heap behavior described above:

* heap/WeakBlock.cpp: Added.
* heap/WeakBlock.h: Added.
* heap/WeakHandleOwner.cpp: Added.
* heap/WeakHandleOwner.h: Added.
* heap/WeakHeap.cpp: Added.
* heap/WeakHeap.h: Added.
* heap/WeakImpl.h: Added.

One interesting difference from the old heap is that we don't allow
clients to overwrite a WeakImpl after allocating it, and we don't recycle
WeakImpls prior to garbage collection. This is required for lazy finalization,
but it will also help us esablish a useful invariant in the future: allocating
a WeakImpl will be a binding contract to run a finalizer at some point in the
future, even if the WeakImpl is later deallocated.

* jit/JITStubs.cpp:
(JSC::JITThunks::hostFunctionStub): Check the Weak<T> for ! instead of
its JSValue, since that's our API contract now, and the JSValue might
be stale.

* runtime/JSCell.h:
(JSC::jsCast): Allow casting NULL pointers because it's useful and harmless.

* runtime/Structure.cpp:
(JSC::StructureTransitionTable::add): I can't remember why I did this.

* runtime/StructureTransitionTable.h:
* runtime/WeakGCMap.h: I had to update these classes because they allocate
and deallocate weak pointers manually. They should probably stop doing that.

Source/WebCore:

Updated WebCore for Weak<T> API changes.

* bindings/js/DOMWrapperWorld.cpp:
(WebCore::JSStringOwner::finalize): We're not allowed to get() a dead Weak<T>
anymore, so use the debug-only was() helper function instead.

* bindings/js/JSDOMBinding.h:
(WebCore::uncacheWrapper): Ditto.

* bindings/js/JSNodeCustom.h:
(WebCore::setInlineCachedWrapper):
(WebCore::clearInlineCachedWrapper): We're not allowed to get() a dead
Weak<T>, so I had to push down these ASSERTs into ScriptWrappable.

* bindings/js/JSNodeFilterCondition.cpp:
(WebCore::JSNodeFilterCondition::acceptNode): Updated for non-Handle-ness
of Weak<T>.

* bindings/js/ScriptWrappable.h:
(WebCore::ScriptWrappable::setWrapper):
(WebCore::ScriptWrappable::clearWrapper): Use was(), as above.

Source/WebKit2:

Updated for API change.

* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
(WebKit::NPRuntimeObjectMap::finalize):

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

42 files changed:
Source/JavaScriptCore/API/JSCallbackObject.cpp
Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.gypi
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/heap/Handle.h
Source/JavaScriptCore/heap/HandleHeap.cpp
Source/JavaScriptCore/heap/HandleHeap.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/heap/MarkedSpace.cpp
Source/JavaScriptCore/heap/MarkedSpace.h
Source/JavaScriptCore/heap/PassWeak.h
Source/JavaScriptCore/heap/Strong.h
Source/JavaScriptCore/heap/Weak.h
Source/JavaScriptCore/heap/WeakBlock.cpp [new file with mode: 0644]
Source/JavaScriptCore/heap/WeakBlock.h [new file with mode: 0644]
Source/JavaScriptCore/heap/WeakHandleOwner.cpp [new file with mode: 0644]
Source/JavaScriptCore/heap/WeakHandleOwner.h [new file with mode: 0644]
Source/JavaScriptCore/heap/WeakHeap.cpp [new file with mode: 0644]
Source/JavaScriptCore/heap/WeakHeap.h [new file with mode: 0644]
Source/JavaScriptCore/heap/WeakImpl.h [new file with mode: 0644]
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/StructureTransitionTable.h
Source/JavaScriptCore/runtime/WeakGCMap.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/DOMWrapperWorld.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSNodeCustom.h
Source/WebCore/bindings/js/JSNodeFilterCondition.cpp
Source/WebCore/bindings/js/ScriptWrappable.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp
Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp
Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp

index ef9cb92..5dba9a0 100644 (file)
@@ -65,8 +65,7 @@ void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context)
     for (; jsClass; jsClass = jsClass->parentClass)
         if (JSObjectFinalizeCallback finalize = jsClass->finalize)
             finalize(thisRef);
-    HandleSlot slot = handle.slot();
-    HandleHeap::heapFor(slot)->deallocate(slot);
+    WeakHeap::deallocate(WeakImpl::asWeakImpl(handle.slot()));
 }
     
 } // namespace JSC
index e6bb884..c1e8246 100644 (file)
@@ -102,14 +102,11 @@ void JSCallbackObject<Parent>::init(ExecState* exec)
         initialize(toRef(exec), toRef(this));
     }
 
-    bool needsFinalizer = false;
-    for (JSClassRef jsClassPtr = classRef(); jsClassPtr && !needsFinalizer; jsClassPtr = jsClassPtr->parentClass)
-        needsFinalizer = jsClassPtr->finalize;
-    if (needsFinalizer) {
-        HandleSlot slot = exec->globalData().heap.handleHeap()->allocate();
-        HandleHeap::heapFor(slot)->makeWeak(slot, m_callbackObjectData.get(), classRef());
-        HandleHeap::heapFor(slot)->writeBarrier(slot, this);
-        *slot = this;
+    for (JSClassRef jsClassPtr = classRef(); jsClassPtr; jsClassPtr = jsClassPtr->parentClass) {
+        if (jsClassPtr->finalize) {
+            exec->globalData().heap.weakHeap()->allocate(this, m_callbackObjectData.get(), classRef());
+            break;
+        }
     }
 }
 
index f6bcc02..223ceb9 100644 (file)
@@ -86,16 +86,19 @@ SET(JavaScriptCore_SOURCES
     dfg/DFGVirtualRegisterAllocationPhase.cpp
 
     heap/CopiedSpace.cpp
+    heap/ConservativeRoots.cpp
     heap/DFGCodeBlocks.cpp
-    heap/Heap.cpp
     heap/HandleHeap.cpp
     heap/HandleStack.cpp
+    heap/Heap.cpp
     heap/MachineStackMarker.cpp
     heap/MarkedAllocator.cpp
     heap/MarkedBlock.cpp
     heap/MarkedSpace.cpp
-    heap/ConservativeRoots.cpp
     heap/MarkStack.cpp
+    heap/WeakHeap.cpp
+    heap/WeakHandleOwner.cpp
+    heap/WeakBlock.cpp
 
     debugger/Debugger.cpp
     debugger/DebuggerActivation.cpp
index 7a1bb83..6b86e73 100644 (file)
@@ -1,3 +1,172 @@
+2012-03-29  Geoffrey Garen  <ggaren@apple.com>
+
+        First step toward incremental Weak<T> finalization
+        https://bugs.webkit.org/show_bug.cgi?id=82670
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements a Weak<T> heap that is compatible with incremental
+        finalization, while making as few behavior changes as possible. The behavior
+        changes it makes are:
+
+        (*) Weak<T>'s raw JSValue no longer reverts to JSValue() automatically --
+        instead, a separate flag indicates that the JSValue is no longer valid.
+        (This is required so that the JSValue can be preserved for later finalization.)
+        Objects dealing with WeakImpls directly must change to check the flag.
+
+        (*) Weak<T> is no longer a subclass of Handle<T>.
+
+        (*) DOM GC performance is different -- 9% faster in the geometric mean,
+        but 15% slower in one specific case:
+                gc-dom1.html: 6%  faster
+                gc-dom2.html: 23% faster
+                gc-dom3.html: 17% faster
+                gc-dom4.html: 15% *slower*
+
+        The key features of this new heap are:
+
+        (*) Each block knows its own state, independent of any other blocks.
+
+        (*) Each block caches its own sweep result.
+
+        (*) The heap visits dead Weak<T>s at the end of GC. (It doesn't
+        mark them yet, since that would be a behavior change.)
+
+        * API/JSCallbackObject.cpp:
+        (JSC::JSCallbackObjectData::finalize):
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::::init): Updated to use the new WeakHeap API.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.gypi:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri: Paid the build system tax since I added some new files.
+
+        * heap/Handle.h: Made WeakBlock a friend and exposed slot() as public,
+        so we can keep passing a Handle<T> to finalizers, to avoid more surface
+        area change in this patch. A follow-up patch should change the type we
+        pass to finalizers.
+
+        * heap/HandleHeap.cpp:
+        (JSC):
+        (JSC::HandleHeap::writeBarrier):
+        (JSC::HandleHeap::isLiveNode):
+        * heap/HandleHeap.h:
+        (JSC):
+        (HandleHeap):
+        (Node):
+        (JSC::HandleHeap::Node::Node): Removed all code related to Weak<T>, since
+        we have a separate WeakHeap now.
+
+        * heap/Heap.cpp:
+        (JSC::Heap::Heap): Removed m_extraCost because extra cost is accounted
+        for through our watermark now. Removed m_waterMark because it was unused.
+
+        (JSC::Heap::destroy): Updated for addition of WeakHeap.
+
+        (JSC::Heap::reportExtraMemoryCostSlowCase): Changed from using its own
+        variable to participating in the watermark strategy. I wanted to standardize
+        WeakHeap and all other Heap clients on this strategy, to make sure it's
+        accurate.
+        (JSC::Heap::markRoots): Updated for addition of WeakHeap. Added WeakHeap
+        dead visit pass, as explained above.
+
+        (JSC::Heap::collect):
+        (JSC::Heap::resetAllocators): Updated for addition of WeakHeap.
+
+        (JSC::Heap::addFinalizer):
+        (JSC::Heap::FinalizerOwner::finalize): Updated for new Weak<T> API.
+
+        * heap/Heap.h:
+        (JSC::Heap::weakHeap):
+        (Heap):
+        (JSC::Heap::addToWaterMark): Added a way to participate in the watermarking
+        strategy, since this is the best way for WeakHeap to report its memory
+        cost. (I plan to update this in a follow-up patch to make it more accurate,
+        but for now it is not less accurate than it used to be.)
+
+        * heap/MarkedSpace.cpp:
+        (JSC::MarkedSpace::MarkedSpace):
+        (JSC::MarkedSpace::resetAllocators):
+        * heap/MarkedSpace.h:
+        (MarkedSpace):
+        (JSC::MarkedSpace::addToWaterMark):
+        (JSC::MarkedSpace::didConsumeFreeList): Removed m_nurseryWaterMark because
+        it was unused, and I didn't want to update WeakHeap to keep an usused
+        variable working. Added API for above.
+
+        * heap/PassWeak.h:
+        (JSC):
+        (WeakImplAccessor):
+        (PassWeak):
+        (JSC::::operator):
+        (JSC::::get):
+        (JSC::::was):
+        (JSC::::PassWeak):
+        (JSC::::~PassWeak):
+        (JSC::UnspecifiedBoolType):
+        (JSC::::leakImpl):
+        (JSC::adoptWeak):
+        * heap/Strong.h:
+        (JSC::Strong::operator!):
+        (Strong):
+        (JSC::Strong::operator UnspecifiedBoolType*):
+        (JSC::Strong::get):
+        * heap/Weak.h:
+        (Weak):
+        (JSC::::Weak):
+        (JSC):
+        (JSC::::isHashTableDeletedValue):
+        (JSC::::~Weak):
+        (JSC::::swap):
+        (JSC::=):
+        (JSC::::operator):
+        (JSC::UnspecifiedBoolType):
+        (JSC::::release):
+        (JSC::::clear):
+        (JSC::::hashTableDeletedValue): Lots of code changes here, but they boil
+        down to two things:
+
+        (*) Allocate WeakImpls from the WeakHeap instead of Handles from the HandleHeap.
+
+        (*) Explicitly check WeakImpl::state() for non-liveness before returning
+        a value (explained above).
+
+        These files implement the new Weak<T> heap behavior described above:
+
+        * heap/WeakBlock.cpp: Added.
+        * heap/WeakBlock.h: Added.
+        * heap/WeakHandleOwner.cpp: Added.
+        * heap/WeakHandleOwner.h: Added.
+        * heap/WeakHeap.cpp: Added.
+        * heap/WeakHeap.h: Added.
+        * heap/WeakImpl.h: Added.
+
+        One interesting difference from the old heap is that we don't allow
+        clients to overwrite a WeakImpl after allocating it, and we don't recycle
+        WeakImpls prior to garbage collection. This is required for lazy finalization,
+        but it will also help us esablish a useful invariant in the future: allocating
+        a WeakImpl will be a binding contract to run a finalizer at some point in the
+        future, even if the WeakImpl is later deallocated.
+
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::hostFunctionStub): Check the Weak<T> for ! instead of
+        its JSValue, since that's our API contract now, and the JSValue might
+        be stale.
+
+        * runtime/JSCell.h:
+        (JSC::jsCast): Allow casting NULL pointers because it's useful and harmless.
+
+        * runtime/Structure.cpp:
+        (JSC::StructureTransitionTable::add): I can't remember why I did this.
+
+        * runtime/StructureTransitionTable.h:
+        * runtime/WeakGCMap.h: I had to update these classes because they allocate
+        and deallocate weak pointers manually. They should probably stop doing that.
+
 2012-04-03  Keishi Hattori  <keishi@webkit.org>
 
         Disable ENABLE_DATALIST for now
index 012a83c..7d0325f 100644 (file)
@@ -250,6 +250,9 @@ javascriptcore_sources += \
        Source/JavaScriptCore/heap/VTableSpectrum.cpp \
        Source/JavaScriptCore/heap/VTableSpectrum.h \
        Source/JavaScriptCore/heap/Weak.h \
+       Source/JavaScriptCore/heap/WeakBlock.cpp \
+       Source/JavaScriptCore/heap/WeakHeap.cpp \
+       Source/JavaScriptCore/heap/WeakHandleOwner.cpp \
        Source/JavaScriptCore/heap/WeakReferenceHarvester.h \
        Source/JavaScriptCore/heap/WriteBarrierSupport.cpp \
        Source/JavaScriptCore/heap/WriteBarrierSupport.h \
index c07b391..ec8a268 100644 (file)
             'bytecompiler/NodesCodegen.cpp',
             'bytecompiler/RegisterID.h',
             'heap/ConservativeRoots.cpp',
+            'heap/WeakHeap.cpp',
+            'heap/WeakHandleOwner.cpp',
+            'heap/WeakBlock.cpp',
             'heap/HandleHeap.cpp',
             'heap/HandleStack.cpp',
             'heap/Heap.cpp',
index 7ffa6c1..8603a80 100644 (file)
@@ -5,9 +5,9 @@ EXPORTS
     ??$strtod@$0A@$00@WTF@@YANPBDPAPAD@Z
     ??$strtod@$0A@$0A@@WTF@@YANPBDPAPAD@Z
     ??0ArrayBufferView@WTF@@IAE@V?$PassRefPtr@VArrayBuffer@WTF@@@1@I@Z
+    ??0Collator@WTF@@QAE@PBD@Z
     ??0CString@WTF@@QAE@PBD@Z
     ??0CString@WTF@@QAE@PBDI@Z
-    ??0Collator@WTF@@QAE@PBD@Z
     ??0DateInstance@JSC@@IAE@PAVExecState@1@PAVStructure@1@@Z
     ??0DefaultGCActivityCallback@JSC@@QAE@PAVHeap@1@@Z
     ??0DropAllLocks@JSLock@JSC@@QAE@W4JSLockBehavior@2@@Z
@@ -25,10 +25,10 @@ EXPORTS
     ??0StringObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@@Z
     ??0Structure@JSC@@AAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@VJSValue@1@ABVTypeInfo@1@PBUClassInfo@1@@Z
     ??0ThreadCondition@WTF@@QAE@XZ
-    ??0UString@JSC@@QAE@PBD@Z
-    ??0UString@JSC@@QAE@PBDI@Z
     ??0UString@JSC@@QAE@PB_W@Z
     ??0UString@JSC@@QAE@PB_WI@Z
+    ??0UString@JSC@@QAE@PBD@Z
+    ??0UString@JSC@@QAE@PBDI@Z
     ??0WTFThreadData@WTF@@QAE@XZ
     ??0YarrPattern@Yarr@JSC@@QAE@ABVUString@2@_N1PAPBD@Z
     ??1ArrayBufferView@WTF@@UAE@XZ
@@ -42,15 +42,10 @@ EXPORTS
     ??1RefCountedLeakCounter@WTF@@QAE@XZ
     ??1SourceProviderCache@JSC@@QAE@XZ
     ??1ThreadCondition@WTF@@QAE@XZ
-    ??1WTFThreadData@WTF@@QAE@XZ
     ??1WeakHandleOwner@JSC@@UAE@XZ
+    ??1WTFThreadData@WTF@@QAE@XZ
     ??8JSC@@YA_NABVUString@0@0@Z
     ??8WTF@@YA_NABVCString@0@0@Z
-    ?EcmaScriptConverter@DoubleToStringConverter@double_conversion@WTF@@SAABV123@XZ
-    ?ToExponential@DoubleToStringConverter@double_conversion@WTF@@QBE_NNHPAVStringBuilder@23@@Z
-    ?ToFixed@DoubleToStringConverter@double_conversion@WTF@@QBE_NNHPAVStringBuilder@23@@Z
-    ?ToPrecision@DoubleToStringConverter@double_conversion@WTF@@QBE_NNHPAVStringBuilder@23@@Z
-    ?ToShortest@DoubleToStringConverter@double_conversion@WTF@@QBE_NNPAVStringBuilder@23@@Z
     ?absoluteTimeToWaitTimeoutInterval@WTF@@YAKN@Z
     ?activityCallback@Heap@JSC@@QAEPAVGCActivityCallback@2@XZ
     ?add@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBD@Z
@@ -69,8 +64,8 @@ EXPORTS
     ?addStaticGlobals@JSGlobalObject@JSC@@IAEXPAUGlobalPropertyInfo@12@H@Z
     ?allocatePropertyStorage@JSObject@JSC@@QAEXAAVJSGlobalData@2@II@Z
     ?allocateSlowCase@MarkedAllocator@JSC@@AAEPAXXZ
-    ?append@StringBuilder@WTF@@QAEXPBEI@Z
     ?append@StringBuilder@WTF@@QAEXPB_WI@Z
+    ?append@StringBuilder@WTF@@QAEXPBEI@Z
     ?ascii@UString@JSC@@QBE?AVCString@WTF@@XZ
     ?attach@Debugger@JSC@@QAEXPAVJSGlobalObject@2@@Z
     ?broadcast@ThreadCondition@WTF@@QAEXXZ
@@ -78,10 +73,10 @@ EXPORTS
     ?bufferLengthForStringExponential@DecimalNumber@WTF@@QBEIXZ
     ?byteCompile@Yarr@JSC@@YA?AV?$PassOwnPtr@UBytecodePattern@Yarr@JSC@@@WTF@@AAUYarrPattern@12@PAVBumpPointerAllocator@4@@Z
     ?byteSize@SourceProviderCache@JSC@@QBEIXZ
+    ?calculatedFunctionName@DebuggerCallFrame@JSC@@QBE?AVUString@2@XZ
     ?calculateDSTOffset@WTF@@YANNN@Z
     ?calculateStringHashAndLengthFromUTF8@Unicode@WTF@@YAIPBD0AAI1@Z
     ?calculateUTCOffset@WTF@@YAHXZ
-    ?calculatedFunctionName@DebuggerCallFrame@JSC@@QBE?AVUString@2@XZ
     ?call@JSC@@YA?AVJSValue@1@PAVExecState@1@V21@W4CallType@1@ABTCallData@1@1ABVArgList@1@@Z
     ?callHostFunctionAsConstructor@JSC@@YI_JPAVExecState@1@@Z
     ?callOnMainThread@WTF@@YAXP6AXPAX@Z0@Z
@@ -91,8 +86,8 @@ EXPORTS
     ?changePrototypeTransition@Structure@JSC@@SAPAV12@AAVJSGlobalData@2@PAV12@VJSValue@2@@Z
     ?checkCurrentIdentifierTable@Identifier@JSC@@CAXPAVExecState@2@@Z
     ?checkCurrentIdentifierTable@Identifier@JSC@@CAXPAVJSGlobalData@2@@Z
-    ?checkSyntax@JSC@@YA_NPAVExecState@1@ABVSourceCode@1@PAVJSValue@1@@Z
     ?checksum@MD5@WTF@@QAEXAAV?$Vector@E$0BA@@2@@Z
+    ?checkSyntax@JSC@@YA_NPAVExecState@1@ABVSourceCode@1@PAVJSValue@1@@Z
     ?className@JSObject@JSC@@SA?AVUString@2@PBV12@@Z
     ?clear@SourceProviderCache@JSC@@QAEXXZ
     ?clearBuiltinStructures@JSGlobalData@JSC@@QAEXXZ
@@ -164,6 +159,7 @@ EXPORTS
     ?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z
     ?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z
     ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z
+    ?EcmaScriptConverter@DoubleToStringConverter@double_conversion@WTF@@SAABV123@XZ
     ?empty@StringImpl@WTF@@SAPAV12@XZ
     ?enumerable@PropertyDescriptor@JSC@@QBE_NXZ
     ?equalUTF16WithUTF8@Unicode@WTF@@YA_NPB_W0PBD1@Z
@@ -183,6 +179,7 @@ EXPORTS
     ?fastZeroedMalloc@WTF@@YAPAXI@Z
     ?fillGetterPropertySlot@JSObject@JSC@@AAEXAAVPropertySlot@2@PAV?$WriteBarrierBase@W4Unknown@JSC@@@2@@Z
     ?finalize@WeakHandleOwner@JSC@@UAEXV?$Handle@W4Unknown@JSC@@@2@PAX@Z
+    ?findAllocator@WeakHeap@JSC@@AAEPAUFreeCell@WeakBlock@2@XZ
     ?finishCreation@DateInstance@JSC@@IAEXAAVJSGlobalData@2@N@Z
     ?finishCreation@InternalFunction@JSC@@IAEXAAVJSGlobalData@2@ABVIdentifier@2@@Z
     ?finishCreation@JSArray@JSC@@IAEXAAVJSGlobalData@2@I@Z
@@ -220,10 +217,10 @@ EXPORTS
     ?globalExec@JSGlobalObject@JSC@@QAEPAVExecState@2@XZ
     ?globalObjectCount@Heap@JSC@@QAEIXZ
     ?grow@HandleHeap@JSC@@AAEXXZ
+    ?hashSlowCase@StringImpl@WTF@@ABEIXZ
     ?hasInstance@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VJSValue@2@2@Z
     ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@ABVIdentifier@2@@Z
     ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z
-    ?hashSlowCase@StringImpl@WTF@@ABEIXZ
     ?heap@Heap@JSC@@SAPAV12@VJSValue@2@@Z
     ?increment@RefCountedLeakCounter@WTF@@QAEXXZ
     ?init@AtomicString@WTF@@SAXXZ
@@ -311,10 +308,10 @@ EXPORTS
     ?setOrderLowerFirst@Collator@WTF@@QAEX_N@Z
     ?setPrototype@JSObject@JSC@@QAEXAAVJSGlobalData@2@VJSValue@2@@Z
     ?setSetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z
+    ?setter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ
     ?setUndefined@PropertyDescriptor@JSC@@QAEXXZ
     ?setUpStaticFunctionSlot@JSC@@YA_NPAVExecState@1@PBVHashEntry@1@PAVJSObject@1@ABVIdentifier@1@AAVPropertySlot@1@@Z
     ?setWritable@PropertyDescriptor@JSC@@QAEX_N@Z
-    ?setter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ
     ?shrinkToFit@StringBuilder@WTF@@QAEXXZ
     ?signal@ThreadCondition@WTF@@QAEXXZ
     ?singleCharacterStringRep@SmallStrings@JSC@@QAEPAVStringImpl@WTF@@E@Z
@@ -340,11 +337,15 @@ EXPORTS
     ?tlsKeyCount@WTF@@YAAAJXZ
     ?tlsKeys@WTF@@YAPAKXZ
     ?toBoolean@JSString@JSC@@QBE_NPAVExecState@2@@Z
+    ?ToExponential@DoubleToStringConverter@double_conversion@WTF@@QBE_NNHPAVStringBuilder@23@@Z
+    ?ToFixed@DoubleToStringConverter@double_conversion@WTF@@QBE_NNHPAVStringBuilder@23@@Z
     ?toInt32@JSC@@YAHN@Z
     ?toInteger@JSValue@JSC@@QBENPAVExecState@2@@Z
     ?toNumberSlowCase@JSValue@JSC@@ABENPAVExecState@2@@Z
     ?toObject@JSCell@JSC@@QBEPAVJSObject@2@PAVExecState@2@PAVJSGlobalObject@2@@Z
     ?toObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@PAVJSGlobalObject@2@@Z
+    ?ToPrecision@DoubleToStringConverter@double_conversion@WTF@@QBE_NNHPAVStringBuilder@23@@Z
+    ?ToShortest@DoubleToStringConverter@double_conversion@WTF@@QBE_NNPAVStringBuilder@23@@Z
     ?toString@JSObject@JSC@@QBEPAVJSString@2@PAVExecState@2@@Z
     ?toStringDecimal@DecimalNumber@WTF@@QBEIPA_WI@Z
     ?toStringExponential@DecimalNumber@WTF@@QBEIPA_WI@Z
index 6b359f4..2fcdc38 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\heap\WeakBlock.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\WeakBlock.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\WeakHeap.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\WeakHeap.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\WeakImpl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\WeakHandleOwner.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\WeakHandleOwner.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\heap\HandleStack.cpp"
                                >
                        </File>
index d663889..125e43b 100644 (file)
                14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A6581A0F4E36F4000150FD /* JITStubs.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14D2F3DA139F4BE200491031 /* MarkedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14D2F3D8139F4BE200491031 /* MarkedSpace.cpp */; };
                14D2F3DB139F4BE200491031 /* MarkedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D2F3D9139F4BE200491031 /* MarkedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */; };
+               14E84F9F14EE1ACC00D6D5D4 /* WeakBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               14E84FA014EE1ACC00D6D5D4 /* WeakHeap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14E84F9B14EE1ACC00D6D5D4 /* WeakHeap.cpp */; };
+               14E84FA114EE1ACC00D6D5D4 /* WeakHeap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9C14EE1ACC00D6D5D4 /* WeakHeap.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14E9D17B107EC469004DDA21 /* JSGlobalObjectFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */; };
+               14F7256514EE265E00B1652B /* WeakHandleOwner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14F7256314EE265E00B1652B /* WeakHandleOwner.cpp */; };
+               14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F7256414EE265E00B1652B /* WeakHandleOwner.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F97446138C853E00DA1C67 /* HeapRootVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41359CF30FDD89AD00206180 /* DateConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateConversion.h */; };
                451539B912DC994500EF7AC4 /* Yarr.h in Headers */ = {isa = PBXBuildFile; fileRef = 451539B812DC994500EF7AC4 /* Yarr.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = "<group>"; };
                14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSActivation.cpp; sourceTree = "<group>"; };
                14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObject.cpp; sourceTree = "<group>"; };
+               14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakBlock.cpp; sourceTree = "<group>"; };
+               14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakBlock.h; sourceTree = "<group>"; };
+               14E84F9B14EE1ACC00D6D5D4 /* WeakHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakHeap.cpp; sourceTree = "<group>"; };
+               14E84F9C14EE1ACC00D6D5D4 /* WeakHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakHeap.h; sourceTree = "<group>"; };
+               14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakImpl.h; sourceTree = "<group>"; };
                14F252560D08DD8D004ECFFF /* JSVariableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVariableObject.h; sourceTree = "<group>"; };
+               14F7256314EE265E00B1652B /* WeakHandleOwner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakHandleOwner.cpp; sourceTree = "<group>"; };
+               14F7256414EE265E00B1652B /* WeakHandleOwner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakHandleOwner.h; sourceTree = "<group>"; };
                14F97446138C853E00DA1C67 /* HeapRootVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapRootVisitor.h; sourceTree = "<group>"; };
                1C9051420BA9E8A70081E9D0 /* Version.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = "<group>"; };
                1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = JavaScriptCore.xcconfig; sourceTree = "<group>"; };
                                0FC815121405118600CFA603 /* VTableSpectrum.cpp */,
                                0FC815141405118D00CFA603 /* VTableSpectrum.h */,
                                142E3133134FF0A600AFADB5 /* Weak.h */,
+                               14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */,
+                               14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */,
+                               14F7256314EE265E00B1652B /* WeakHandleOwner.cpp */,
+                               14F7256414EE265E00B1652B /* WeakHandleOwner.h */,
+                               14E84F9B14EE1ACC00D6D5D4 /* WeakHeap.cpp */,
+                               14E84F9C14EE1ACC00D6D5D4 /* WeakHeap.h */,
+                               14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */,
                                0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */,
                                0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */,
                                0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
                                0FFFC95E14EF90B700C72532 /* DFGPredictionPropagationPhase.h in Headers */,
                                0FFFC96014EF90BD00C72532 /* DFGVirtualRegisterAllocationPhase.h in Headers */,
                                1497209114EB831500FEB1B7 /* PassWeak.h in Headers */,
+                               14E84F9F14EE1ACC00D6D5D4 /* WeakBlock.h in Headers */,
+                               14E84FA114EE1ACC00D6D5D4 /* WeakHeap.h in Headers */,
+                               14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */,
+                               14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */,
                                0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */,
                                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */,
                                0F0776BF14FF002B00102332 /* JITCompilationEffort.h in Headers */,
                                86B5826914D2797000A9C306 /* CodeProfiling.cpp in Sources */,
                                C2B916C514DA040C00CBAC86 /* MarkedAllocator.cpp in Sources */,
                                0F9FC8C314E1B5FE00D52AE0 /* PolymorphicPutByIdList.cpp in Sources */,
+                               14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */,
+                               14E84FA014EE1ACC00D6D5D4 /* WeakHeap.cpp in Sources */,
+                               14F7256514EE265E00B1652B /* WeakHandleOwner.cpp in Sources */,
                                0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */,
                                0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */,
                                0FFFC95B14EF90AD00C72532 /* DFGPhase.cpp in Sources */,
index 2bc8089..2797e10 100644 (file)
@@ -71,6 +71,9 @@ SOURCES += \
     heap/CopiedSpace.cpp \
     heap/ConservativeRoots.cpp \
     heap/DFGCodeBlocks.cpp \
+    heap/WeakHeap.cpp \
+    heap/WeakHandleOwner.cpp \
+    heap/WeakBlock.cpp \
     heap/HandleHeap.cpp \
     heap/HandleStack.cpp \
     heap/Heap.cpp \
index 6f46774..13312c8 100644 (file)
@@ -59,6 +59,8 @@ public:
     typedef JSValue (HandleBase::*UnspecifiedBoolType);
     operator UnspecifiedBoolType*() const { return (m_slot && *m_slot) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
 
+    HandleSlot slot() const { return m_slot; }
+
 protected:
     HandleBase(HandleSlot slot)
         : m_slot(slot)
@@ -67,7 +69,6 @@ protected:
     
     void swap(HandleBase& other) { std::swap(m_slot, other.m_slot); }
 
-    HandleSlot slot() const { return m_slot; }
     void setSlot(HandleSlot slot)
     {
         m_slot = slot;
@@ -133,6 +134,7 @@ protected:
     
 private:
     friend class HandleHeap;
+    friend class WeakBlock;
 
     static Handle<T> wrapSlot(HandleSlot slot)
     {
index 2402f7e..38b3371 100644 (file)
 
 namespace JSC {
 
-WeakHandleOwner::~WeakHandleOwner()
-{
-}
-
-bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&)
-{
-    return false;
-}
-
-void WeakHandleOwner::finalize(Handle<Unknown>, void*)
-{
-}
-
 HandleHeap::HandleHeap(JSGlobalData* globalData)
     : m_globalData(globalData)
     , m_nextToFinalize(0)
@@ -73,62 +60,6 @@ void HandleHeap::visitStrongHandles(HeapRootVisitor& heapRootVisitor)
     }
 }
 
-void HandleHeap::visitWeakHandles(HeapRootVisitor& heapRootVisitor)
-{
-    SlotVisitor& visitor = heapRootVisitor.visitor();
-
-    Node* end = m_weakList.end();
-    for (Node* node = m_weakList.begin(); node != end; node = node->next()) {
-#if ENABLE(GC_VALIDATION)
-        if (!isValidWeakNode(node))
-            CRASH();
-#endif
-        JSCell* cell = node->slot()->asCell();
-        if (Heap::isMarked(cell))
-            continue;
-
-        WeakHandleOwner* weakOwner = node->weakOwner();
-        if (!weakOwner)
-            continue;
-
-        if (!weakOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(node->slot()), node->weakOwnerContext(), visitor))
-            continue;
-
-        heapRootVisitor.visit(node->slot());
-    }
-}
-
-void HandleHeap::finalizeWeakHandles()
-{
-    Node* end = m_weakList.end();
-    for (Node* node = m_weakList.begin(); node != end; node = m_nextToFinalize) {
-        m_nextToFinalize = node->next();
-#if ENABLE(GC_VALIDATION)
-        if (!isValidWeakNode(node))
-            CRASH();
-#endif
-
-        JSCell* cell = node->slot()->asCell();
-        if (Heap::isMarked(cell))
-            continue;
-
-        if (WeakHandleOwner* weakOwner = node->weakOwner()) {
-            weakOwner->finalize(Handle<Unknown>::wrapSlot(node->slot()), node->weakOwnerContext());
-            if (m_nextToFinalize != node->next()) // Owner deallocated node.
-                continue;
-        }
-#if ENABLE(GC_VALIDATION)
-        if (!isLiveNode(node))
-            CRASH();
-#endif
-        *node->slot() = JSValue();
-        SentinelLinkedList<Node>::remove(node);
-        m_immediateList.push(node);
-    }
-    
-    m_nextToFinalize = 0;
-}
-
 void HandleHeap::writeBarrier(HandleSlot slot, const JSValue& value)
 {
     // Forbid assignment to handles during the finalization phase, since it would violate many GC invariants.
@@ -150,15 +81,6 @@ void HandleHeap::writeBarrier(HandleSlot slot, const JSValue& value)
         return;
     }
 
-    if (node->isWeak()) {
-        m_weakList.push(node);
-#if ENABLE(GC_VALIDATION)
-        if (!isLiveNode(node))
-            CRASH();
-#endif
-        return;
-    }
-
     m_strongList.push(node);
 #if ENABLE(GC_VALIDATION)
     if (!isLiveNode(node))
@@ -188,24 +110,6 @@ bool HandleHeap::isLiveNode(Node* node)
         
     return true;
 }
-
-bool HandleHeap::isValidWeakNode(Node* node)
-{
-    if (!isLiveNode(node))
-        return false;
-    if (!node->isWeak())
-        return false;
-
-    JSValue value = *node->slot();
-    if (!value || !value.isCell())
-        return false;
-
-    JSCell* cell = value.asCell();
-    if (!cell || !cell->structure())
-        return false;
-
-    return true;
-}
 #endif
 
 } // namespace JSC
index c9ee11b..c2cba20 100644 (file)
@@ -40,13 +40,6 @@ class JSGlobalData;
 class JSValue;
 class SlotVisitor;
 
-class JS_EXPORT_PRIVATE WeakHandleOwner {
-public:
-    virtual ~WeakHandleOwner();
-    virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&);
-    virtual void finalize(Handle<Unknown>, void* context);
-};
-
 class HandleHeap {
 public:
     static HandleHeap* heapFor(HandleSlot);
@@ -58,20 +51,10 @@ public:
     HandleSlot allocate();
     void deallocate(HandleSlot);
 
-    void makeWeak(HandleSlot, WeakHandleOwner* = 0, void* context = 0);
-    HandleSlot copyWeak(HandleSlot);
-
     void visitStrongHandles(HeapRootVisitor&);
-    void visitWeakHandles(HeapRootVisitor&);
-    void finalizeWeakHandles();
 
     JS_EXPORT_PRIVATE void writeBarrier(HandleSlot, const JSValue&);
 
-#if !ASSERT_DISABLED
-    bool hasWeakOwner(HandleSlot, WeakHandleOwner*);
-    bool hasFinalizer(HandleSlot);
-#endif
-
     unsigned protectedGlobalObjectCount();
 
     template<typename Functor> void forEachStrongHandle(Functor&, const HashCountedSet<JSCell*>& skipSet);
@@ -85,12 +68,6 @@ private:
         HandleSlot slot();
         HandleHeap* handleHeap();
 
-        void makeWeak(WeakHandleOwner*, void* context);
-        bool isWeak();
-        
-        WeakHandleOwner* weakOwner();
-        void* weakOwnerContext();
-
         void setPrev(Node*);
         Node* prev();
 
@@ -98,12 +75,8 @@ private:
         Node* next();
 
     private:
-        WeakHandleOwner* emptyWeakOwner();
-
         JSValue m_value;
         HandleHeap* m_handleHeap;
-        WeakHandleOwner* m_weakOwner;
-        void* m_weakOwnerContext;
         Node* m_prev;
         Node* m_next;
     };
@@ -114,7 +87,6 @@ private:
     JS_EXPORT_PRIVATE void grow();
     
 #if ENABLE(GC_VALIDATION) || !ASSERT_DISABLED
-    bool isValidWeakNode(Node*);
     bool isLiveNode(Node*);
 #endif
 
@@ -122,7 +94,6 @@ private:
     BlockStack<Node> m_blockStack;
 
     SentinelLinkedList<Node> m_strongList;
-    SentinelLinkedList<Node> m_weakList;
     SentinelLinkedList<Node> m_immediateList;
     SinglyLinkedList<Node> m_freeList;
     Node* m_nextToFinalize;
@@ -175,49 +146,8 @@ inline void HandleHeap::deallocate(HandleSlot handle)
     m_freeList.push(node);
 }
 
-inline HandleSlot HandleHeap::copyWeak(HandleSlot other)
-{
-    Node* node = toNode(allocate());
-    node->makeWeak(toNode(other)->weakOwner(), toNode(other)->weakOwnerContext());
-    writeBarrier(node->slot(), *other);
-    *node->slot() = *other;
-    return toHandle(node);
-}
-
-inline void HandleHeap::makeWeak(HandleSlot handle, WeakHandleOwner* weakOwner, void* context)
-{
-    // Forbid assignment to handles during the finalization phase, since it would violate many GC invariants.
-    // File a bug with stack trace if you hit this.
-    if (m_nextToFinalize)
-        CRASH();
-    Node* node = toNode(handle);
-    node->makeWeak(weakOwner, context);
-
-    SentinelLinkedList<Node>::remove(node);
-    if (!*handle || !handle->isCell()) {
-        m_immediateList.push(node);
-        return;
-    }
-
-    m_weakList.push(node);
-}
-
-#if !ASSERT_DISABLED
-inline bool HandleHeap::hasWeakOwner(HandleSlot handle, WeakHandleOwner* weakOwner)
-{
-    return toNode(handle)->weakOwner() == weakOwner;
-}
-
-inline bool HandleHeap::hasFinalizer(HandleSlot handle)
-{
-    return toNode(handle)->weakOwner();
-}
-#endif
-
 inline HandleHeap::Node::Node(HandleHeap* handleHeap)
     : m_handleHeap(handleHeap)
-    , m_weakOwner(0)
-    , m_weakOwnerContext(0)
     , m_prev(0)
     , m_next(0)
 {
@@ -225,8 +155,6 @@ inline HandleHeap::Node::Node(HandleHeap* handleHeap)
 
 inline HandleHeap::Node::Node(WTF::SentinelTag)
     : m_handleHeap(0)
-    , m_weakOwner(0)
-    , m_weakOwnerContext(0)
     , m_prev(0)
     , m_next(0)
 {
@@ -242,28 +170,6 @@ inline HandleHeap* HandleHeap::Node::handleHeap()
     return m_handleHeap;
 }
 
-inline void HandleHeap::Node::makeWeak(WeakHandleOwner* weakOwner, void* context)
-{
-    m_weakOwner = weakOwner ? weakOwner : emptyWeakOwner();
-    m_weakOwnerContext = context;
-}
-
-inline bool HandleHeap::Node::isWeak()
-{
-    return m_weakOwner; // True for emptyWeakOwner().
-}
-
-inline WeakHandleOwner* HandleHeap::Node::weakOwner()
-{
-    return m_weakOwner == emptyWeakOwner() ? 0 : m_weakOwner; // 0 for emptyWeakOwner().
-}
-
-inline void* HandleHeap::Node::weakOwnerContext()
-{
-    ASSERT(weakOwner());
-    return m_weakOwnerContext;
-}
-
 inline void HandleHeap::Node::setPrev(Node* prev)
 {
     m_prev = prev;
@@ -284,13 +190,6 @@ inline HandleHeap::Node* HandleHeap::Node::next()
     return m_next;
 }
 
-// Sentinel to indicate that a node is weak, but its owner has no meaningful
-// callbacks. This allows us to optimize by skipping such nodes.
-inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner()
-{
-    return reinterpret_cast<WeakHandleOwner*>(-1);
-}
-
 template<typename Functor> void HandleHeap::forEachStrongHandle(Functor& functor, const HashCountedSet<JSCell*>& skipSet)
 {
     Node* end = m_strongList.end();
index c54ba77..a41764f 100644 (file)
@@ -313,18 +313,17 @@ Heap::Heap(JSGlobalData* globalData, HeapSize heapSize)
     : m_heapSize(heapSize)
     , m_minBytesPerCycle(heapSizeForHint(heapSize))
     , m_lastFullGCSize(0)
-    , m_waterMark(0)
     , m_highWaterMark(m_minBytesPerCycle)
     , m_operationInProgress(NoOperation)
     , m_objectSpace(this)
     , m_storageSpace(this)
     , m_blockFreeingThreadShouldQuit(false)
-    , m_extraCost(0)
     , m_markListSet(0)
     , m_activityCallback(DefaultGCActivityCallback::create(this))
     , m_machineThreads(this)
     , m_sharedData(globalData)
     , m_slotVisitor(m_sharedData)
+    , m_weakHeap(this)
     , m_handleHeap(globalData)
     , m_isSafeToCollect(false)
     , m_globalData(globalData)
@@ -376,7 +375,7 @@ void Heap::destroy()
     canonicalizeCellLivenessData();
     clearMarks();
 
-    m_handleHeap.finalizeWeakHandles();
+    m_weakHeap.finalizeAll();
     m_globalData->smallStrings.finalizeSmallStrings();
     shrink();
     m_storageSpace.destroy();
@@ -466,9 +465,7 @@ void Heap::reportExtraMemoryCostSlowCase(size_t cost)
     // if a large value survives one garbage collection, there is not much point to
     // collecting more frequently as long as it stays alive.
 
-    if (m_extraCost > maxExtraCost && m_extraCost > highWaterMark() / 2)
-        collectAllGarbage();
-    m_extraCost += cost;
+    addToWaterMark(cost);
 }
 
 void Heap::protect(JSValue k)
@@ -687,12 +684,12 @@ void Heap::markRoots(bool fullGC)
 #endif
     }
 
-    // Weak handles must be marked last, because their owners use the set of
-    // opaque roots to determine reachability.
+    // Weak references must be marked last because their liveness depends on
+    // the liveness of the rest of the object graph.
     {
-        GCPHASE(VisitingWeakHandles);
+        GCPHASE(VisitingLiveWeakHandles);
         while (true) {
-            m_handleHeap.visitWeakHandles(heapRootVisitor);
+            m_weakHeap.visitLiveWeakImpls(heapRootVisitor);
             harvestWeakReferences();
             if (visitor.isEmpty())
                 break;
@@ -705,6 +702,12 @@ void Heap::markRoots(bool fullGC)
             }
         }
     }
+
+    {
+        GCPHASE(VisitingDeadWeakHandles);
+        m_weakHeap.visitDeadWeakImpls(heapRootVisitor);
+    }
+
     GCCOUNTER(VisitedValueCount, visitor.visitCount());
 
     visitor.doneCopying();
@@ -815,7 +818,7 @@ void Heap::collect(SweepToggle sweepToggle)
         
     {
         GCPHASE(FinalizeWeakHandles);
-        m_handleHeap.finalizeWeakHandles();
+        m_weakHeap.sweep();
         m_globalData->smallStrings.finalizeSmallStrings();
     }
     
@@ -846,7 +849,7 @@ void Heap::collect(SweepToggle sweepToggle)
     size_t proportionalBytes = 2 * newSize;
     if (fullGC) {
         m_lastFullGCSize = newSize;
-        setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle));
+        m_highWaterMark = max(proportionalBytes, m_minBytesPerCycle);
     }
     double lastGCEndTime = WTF::currentTime();
     m_lastGCLength = lastGCEndTime - lastGCStartTime;
@@ -862,8 +865,8 @@ void Heap::canonicalizeCellLivenessData()
 
 void Heap::resetAllocators()
 {
-    m_extraCost = 0;
     m_objectSpace.resetAllocators();
+    m_weakHeap.resetAllocator();
 }
 
 void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
@@ -924,15 +927,15 @@ void Heap::releaseFreeBlocks()
 
 void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
 {
-    Weak<JSCell> weak(*globalData(), cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer));
-    weak.leakHandle(); // Balanced by FinalizerOwner::finalize().
+    weakHeap()->allocate(cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
 }
 
 void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context)
 {
-    Weak<JSCell> weak(Weak<JSCell>::Adopt, handle);
+    HandleSlot slot = handle.slot();
     Finalizer finalizer = reinterpret_cast<Finalizer>(context);
-    finalizer(weak.get());
+    finalizer(slot->asCell());
+    WeakHeap::deallocate(WeakImpl::asWeakImpl(slot));
 }
 
 void Heap::addFunctionExecutable(FunctionExecutable* executable)
index c78c856..2c36c1f 100644 (file)
@@ -30,6 +30,8 @@
 #include "MarkedBlockSet.h"
 #include "MarkedSpace.h"
 #include "SlotVisitor.h"
+#include "WeakHandleOwner.h"
+#include "WeakHeap.h"
 #include "WriteBarrierSupport.h"
 #include <wtf/DoublyLinkedList.h>
 #include <wtf/Forward.h>
@@ -136,11 +138,14 @@ namespace JSC {
         template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
         template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
 
+        WeakHeap* weakHeap() { return &m_weakHeap; }
         HandleHeap* handleHeap() { return &m_handleHeap; }
         HandleStack* handleStack() { return &m_handleStack; }
 
         void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
 
+        void addToWaterMark(size_t);
+
         double lastGCLength() { return m_lastGCLength; }
 
         void discardAllCompiledCode();
@@ -160,7 +165,6 @@ namespace JSC {
 
         size_t waterMark();
         size_t highWaterMark();
-        void setHighWaterMark(size_t);
         bool shouldCollect();
 
         static const size_t minExtraCost = 256;
@@ -204,7 +208,6 @@ namespace JSC {
         const HeapSize m_heapSize;
         const size_t m_minBytesPerCycle;
         size_t m_lastFullGCSize;
-        size_t m_waterMark;
         size_t m_highWaterMark;
         
         OperationInProgress m_operationInProgress;
@@ -223,8 +226,6 @@ namespace JSC {
         VTableSpectrum m_destroyedTypeCounts;
 #endif
 
-        size_t m_extraCost;
-
         ProtectCountSet m_protectedValues;
         Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
         HashSet<MarkedArgumentBuffer*>* m_markListSet;
@@ -236,6 +237,7 @@ namespace JSC {
         MarkStackThreadSharedData m_sharedData;
         SlotVisitor m_slotVisitor;
 
+        WeakHeap m_weakHeap;
         HandleHeap m_handleHeap;
         HandleStack m_handleStack;
         DFGCodeBlocks m_dfgCodeBlocks;
@@ -300,9 +302,11 @@ namespace JSC {
         return m_highWaterMark;
     }
 
-    inline void Heap::setHighWaterMark(size_t newHighWaterMark)
+    inline void Heap::addToWaterMark(size_t size)
     {
-        m_highWaterMark = newHighWaterMark;
+        m_objectSpace.addToWaterMark(size);
+        if (waterMark() > highWaterMark())
+            collect(DoNotSweep);
     }
 
 #if ENABLE(GGC)
index bf83901..a7d9da2 100644 (file)
@@ -32,7 +32,6 @@ class Structure;
 
 MarkedSpace::MarkedSpace(Heap* heap)
     : m_waterMark(0)
-    , m_nurseryWaterMark(0)
     , m_heap(heap)
 {
     for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
@@ -49,7 +48,6 @@ MarkedSpace::MarkedSpace(Heap* heap)
 void MarkedSpace::resetAllocators()
 {
     m_waterMark = 0;
-    m_nurseryWaterMark = 0;
 
     for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
         allocatorFor(cellSize).reset();
index b553eb1..2ac053e 100644 (file)
@@ -66,7 +66,7 @@ public:
     void canonicalizeCellLivenessData();
 
     size_t waterMark();
-    size_t nurseryWaterMark();
+    void addToWaterMark(size_t);
 
     typedef HashSet<MarkedBlock*>::iterator BlockIterator;
     
@@ -77,6 +77,7 @@ public:
     
     void shrink();
     void freeBlocks(MarkedBlock* head);
+
     void didAddBlock(MarkedBlock*);
     void didConsumeFreeList(MarkedBlock*);
 
@@ -102,7 +103,6 @@ private:
     Subspace m_normalSpace;
 
     size_t m_waterMark;
-    size_t m_nurseryWaterMark;
     Heap* m_heap;
     MarkedBlockSet m_blocks;
 };
@@ -112,9 +112,9 @@ inline size_t MarkedSpace::waterMark()
     return m_waterMark;
 }
 
-inline size_t MarkedSpace::nurseryWaterMark()
+inline void MarkedSpace::addToWaterMark(size_t size)
 {
-    return m_nurseryWaterMark;
+    m_waterMark += size;
 }
 
 template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachCell(Functor& functor)
@@ -199,7 +199,6 @@ inline void MarkedSpace::didAddBlock(MarkedBlock* block)
 
 inline void MarkedSpace::didConsumeFreeList(MarkedBlock* block)
 {
-    m_nurseryWaterMark += block->capacity() - block->size();
     m_waterMark += block->capacity();
 }
 
index 0d86e6c..557854b 100644 (file)
@@ -26,8 +26,8 @@
 #ifndef PassWeak_h
 #define PassWeak_h
 
+#include "JSCell.h"
 #include <wtf/Assertions.h>
-#include "Handle.h"
 #include <wtf/NullPtr.h>
 #include <wtf/TypeTraits.h>
 
@@ -35,61 +35,164 @@ namespace JSC {
 
 template<typename T> class Weak;
 template<typename T> class PassWeak;
-template<typename T> PassWeak<T> adoptWeak(HandleSlot);
+template<typename T> PassWeak<T> adoptWeak(WeakImpl*);
 
-template<typename T> class PassWeak : public Handle<T> {
-    using Handle<T>::slot;
-    using Handle<T>::setSlot;
+template<typename Base, typename T> class WeakImplAccessor {
+public:
+    typedef T* GetType;
+
+    T* operator->() const;
+    T& operator*() const;
+    GetType get() const;
+
+#if !ASSERT_DISABLED
+    bool was(GetType) const;
+#endif
+};
 
+template<typename Base> class WeakImplAccessor<Base, Unknown> {
 public:
-    typedef typename Handle<T>::ExternalType ExternalType;
+    typedef JSValue GetType;
 
-    PassWeak() : Handle<T>() { }
-    PassWeak(std::nullptr_t) : Handle<T>() { }
+    const JSValue* operator->() const;
+    const JSValue& operator*() const;
+    GetType get() const;
+};
+
+template<typename T> class PassWeak : public WeakImplAccessor<PassWeak<T>, T> {
+public:
+    friend class WeakImplAccessor<PassWeak<T>, T>;
+    typedef typename WeakImplAccessor<PassWeak<T>, T>::GetType GetType;
 
-    PassWeak(JSGlobalData& globalData, ExternalType externalType = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0)
-        : Handle<T>(globalData.heap.handleHeap()->allocate())
-    {
-        HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context);
-        JSValue value = HandleTypes<T>::toJSValue(externalType);
-        HandleHeap::heapFor(slot())->writeBarrier(slot(), value);
-        *slot() = value;
-    }
+    PassWeak();
+    PassWeak(std::nullptr_t);
+    PassWeak(JSGlobalData&, GetType = GetType(), WeakHandleOwner* = 0, void* context = 0);
 
     // It somewhat breaks the type system to allow transfer of ownership out of
     // a const PassWeak. However, it makes it much easier to work with PassWeak
     // temporaries, and we don't have a need to use real const PassWeaks anyway.
-    PassWeak(const PassWeak& o) : Handle<T>(o.leakHandle()) { }
-    template<typename U> PassWeak(const PassWeak<U>& o) : Handle<T>(o.leakHandle()) { }
+    PassWeak(const PassWeak&);
+    template<typename U> PassWeak(const PassWeak<U>&);
 
-    ~PassWeak()
-    {
-        if (!slot())
-            return;
-        HandleHeap::heapFor(slot())->deallocate(slot());
-        setSlot(0);
-    }
+    ~PassWeak();
 
-    ExternalType get() const { return  HandleTypes<T>::getFromSlot(slot()); }
+    bool operator!() const;
 
-    HandleSlot leakHandle() const WARN_UNUSED_RETURN;
+    // This conversion operator allows implicit conversion to bool but not to other integer types.
+    typedef JSValue (PassWeak::*UnspecifiedBoolType);
+    operator UnspecifiedBoolType*() const;
+
+    WeakImpl* leakImpl() const WARN_UNUSED_RETURN;
 
 private:
-    friend PassWeak adoptWeak<T>(HandleSlot);
+    friend PassWeak adoptWeak<T>(WeakImpl*);
+    explicit PassWeak(WeakImpl*);
 
-    explicit PassWeak(HandleSlot slot) : Handle<T>(slot) { }
+    WeakImpl* m_impl;
 };
 
-template<typename T> inline HandleSlot PassWeak<T>::leakHandle() const
+template<typename Base, typename T> inline T* WeakImplAccessor<Base, T>::operator->() const
+{
+    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
+    return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
+}
+
+template<typename Base, typename T> inline T& WeakImplAccessor<Base, T>::operator*() const
+{
+    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
+    return *jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
+}
+
+template<typename Base, typename T> inline typename WeakImplAccessor<Base, T>::GetType WeakImplAccessor<Base, T>::get() const
+{
+    if (!static_cast<const Base*>(this)->m_impl || static_cast<const Base*>(this)->m_impl->state() != WeakImpl::Live)
+        return GetType();
+    return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
+}
+
+#if !ASSERT_DISABLED
+template<typename Base, typename T> inline bool WeakImplAccessor<Base, T>::was(typename WeakImplAccessor<Base, T>::GetType other) const
+{
+    return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell()) == other;
+}
+#endif
+
+template<typename Base> inline const JSValue* WeakImplAccessor<Base, Unknown>::operator->() const
+{
+    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
+    return &static_cast<const Base*>(this)->m_impl->jsValue();
+}
+
+template<typename Base> inline const JSValue& WeakImplAccessor<Base, Unknown>::operator*() const
+{
+    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
+    return static_cast<const Base*>(this)->m_impl->jsValue();
+}
+
+template<typename Base> inline typename WeakImplAccessor<Base, Unknown>::GetType WeakImplAccessor<Base, Unknown>::get() const
+{
+    if (!static_cast<const Base*>(this)->m_impl || static_cast<const Base*>(this)->m_impl->state() != WeakImpl::Live)
+        return GetType();
+    return static_cast<const Base*>(this)->m_impl->jsValue();
+}
+
+template<typename T> inline PassWeak<T>::PassWeak()
+    : m_impl(0)
+{
+}
+
+template<typename T> inline PassWeak<T>::PassWeak(std::nullptr_t)
+    : m_impl(0)
+{
+}
+
+template<typename T> inline PassWeak<T>::PassWeak(JSGlobalData& globalData, typename PassWeak<T>::GetType getType, WeakHandleOwner* weakOwner, void* context)
+    : m_impl(globalData.heap.weakHeap()->allocate(getType, weakOwner, context))
+{
+}
+
+template<typename T> inline PassWeak<T>::PassWeak(const PassWeak& o)
+    : m_impl(o.leakImpl())
+{
+}
+
+template<typename T> template<typename U> inline PassWeak<T>::PassWeak(const PassWeak<U>& o)
+    : m_impl(o.leakImpl())
+{
+}
+
+template<typename T> inline PassWeak<T>::~PassWeak()
+{
+    if (!m_impl)
+        return;
+    WeakHeap::deallocate(m_impl);
+}
+
+template<typename T> inline bool PassWeak<T>::operator!() const
+{
+    return !m_impl || m_impl->state() != WeakImpl::Live || !m_impl->jsValue();
+}
+
+template<typename T> inline PassWeak<T>::operator UnspecifiedBoolType*() const
+{
+    return reinterpret_cast<UnspecifiedBoolType*>(!!*this);
+}
+
+template<typename T> inline PassWeak<T>::PassWeak(WeakImpl* impl)
+: m_impl(impl)
+{
+}
+
+template<typename T> inline WeakImpl* PassWeak<T>::leakImpl() const
 {
-    HandleSlot slot = this->slot();
-    const_cast<PassWeak<T>*>(this)->setSlot(0);
-    return slot;
+    WeakImpl* tmp = 0;
+    std::swap(tmp, const_cast<WeakImpl*&>(m_impl));
+    return tmp;
 }
 
-template<typename T> PassWeak<T> adoptWeak(HandleSlot slot)
+template<typename T> PassWeak<T> inline adoptWeak(WeakImpl* impl)
 {
-    return PassWeak<T>(slot);
+    return PassWeak<T>(impl);
 }
 
 template<typename T, typename U> inline bool operator==(const PassWeak<T>& a, const PassWeak<U>& b) 
index d2f2a22..9874ab8 100644 (file)
@@ -81,11 +81,19 @@ public:
         clear();
     }
 
+    bool operator!() const { return !slot() || !*slot(); }
+
+    // This conversion operator allows implicit conversion to bool but not to other integer types.
+    typedef JSValue (HandleBase::*UnspecifiedBoolType);
+    operator UnspecifiedBoolType*() const { return !!*this ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+
     void swap(Strong& other)
     {
         Handle<T>::swap(other);
     }
 
+    ExternalType get() const { return HandleTypes<T>::getFromSlot(this->slot()); }
+
     void set(JSGlobalData&, ExternalType);
 
     template <typename U> Strong& operator=(const Strong<U>& other)
index 8291e44..b05a484 100644 (file)
 #define Weak_h
 
 #include <wtf/Assertions.h>
-#include "Handle.h"
-#include "HandleHeap.h"
 #include "JSGlobalData.h"
 #include "PassWeak.h"
 
 namespace JSC {
 
-// A weakly referenced handle that becomes 0 when the value it points to is garbage collected.
-template <typename T> class Weak : public Handle<T> {
+template<typename T> class Weak : public WeakImplAccessor<Weak<T>, T> {
     WTF_MAKE_NONCOPYABLE(Weak);
-
-    using Handle<T>::slot;
-    using Handle<T>::setSlot;
-
 public:
-    typedef typename Handle<T>::ExternalType ExternalType;
-
-    Weak()
-        : Handle<T>()
-    {
-    }
-
-    Weak(std::nullptr_t)
-        : Handle<T>()
-    {
-    }
-
-    Weak(JSGlobalData& globalData, ExternalType externalType = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0)
-        : Handle<T>(globalData.heap.handleHeap()->allocate())
-    {
-        HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context);
-        JSValue value = HandleTypes<T>::toJSValue(externalType);
-        HandleHeap::heapFor(slot())->writeBarrier(slot(), value);
-        *slot() = value;
-    }
-
-    enum AdoptTag { Adopt };
-    template<typename U> Weak(AdoptTag, Handle<U> handle)
-        : Handle<T>(handle.slot())
-    {
-        validateCell(get());
-    }
+    friend class WeakImplAccessor<Weak<T>, T>;
+    typedef typename WeakImplAccessor<Weak<T>, T>::GetType GetType;
+
+    Weak();
+    Weak(std::nullptr_t);
+    Weak(JSGlobalData&, GetType = GetType(), WeakHandleOwner* = 0, void* context = 0);
 
     enum HashTableDeletedValueTag { HashTableDeletedValue };
-    bool isHashTableDeletedValue() const { return slot() == hashTableDeletedValue(); }
-    Weak(HashTableDeletedValueTag)
-        : Handle<T>(hashTableDeletedValue())
-    {
-    }
-
-    template<typename U> Weak(const PassWeak<U>& other)
-        : Handle<T>(other.leakHandle())
-    {
-    }
-
-    ~Weak()
-    {
-        clear();
-    }
-
-    void swap(Weak& other)
-    {
-        Handle<T>::swap(other);
-    }
+    bool isHashTableDeletedValue() const;
+    Weak(HashTableDeletedValueTag);
 
-    Weak& operator=(const PassWeak<T>&);
+    template<typename U> Weak(const PassWeak<U>&);
 
-    ExternalType get() const { return  HandleTypes<T>::getFromSlot(slot()); }
-    
-    PassWeak<T> release() { PassWeak<T> tmp = adoptWeak<T>(slot()); setSlot(0); return tmp; }
-
-    void clear()
-    {
-        if (!slot())
-            return;
-        HandleHeap::heapFor(slot())->deallocate(slot());
-        setSlot(0);
-    }
+    ~Weak();
+
+    void swap(Weak&);
+    Weak& operator=(const PassWeak<T>&);
     
-    HandleSlot leakHandle()
-    {
-        ASSERT(HandleHeap::heapFor(slot())->hasFinalizer(slot()));
-        HandleSlot result = slot();
-        setSlot(0);
-        return result;
-    }
+    bool operator!() const;
 
+    // This conversion operator allows implicit conversion to bool but not to other integer types.
+    typedef JSValue (HandleBase::*UnspecifiedBoolType);
+    operator UnspecifiedBoolType*() const;
+
+    PassWeak<T> release();
+    void clear();
+    
 private:
-    static HandleSlot hashTableDeletedValue() { return reinterpret_cast<HandleSlot>(-1); }
+    static WeakImpl* hashTableDeletedValue();
+
+    WeakImpl* m_impl;
 };
 
+template<typename T> inline Weak<T>::Weak()
+    : m_impl(0)
+{
+}
+
+template<typename T> inline Weak<T>::Weak(std::nullptr_t)
+    : m_impl(0)
+{
+}
+
+template<typename T> inline Weak<T>::Weak(JSGlobalData& globalData, typename Weak<T>::GetType getType, WeakHandleOwner* weakOwner, void* context)
+    : m_impl(globalData.heap.weakHeap()->allocate(getType, weakOwner, context))
+{
+}
+
+template<typename T> inline bool Weak<T>::isHashTableDeletedValue() const
+{
+    return m_impl == hashTableDeletedValue();
+}
+
+template<typename T> inline Weak<T>::Weak(typename Weak<T>::HashTableDeletedValueTag)
+    : m_impl(hashTableDeletedValue())
+{
+}
+
+template<typename T> template<typename U>  inline Weak<T>::Weak(const PassWeak<U>& other)
+    : m_impl(other.leakImpl())
+{
+}
+
+template<typename T> inline Weak<T>::~Weak()
+{
+    clear();
+}
+
 template<class T> inline void swap(Weak<T>& a, Weak<T>& b)
 {
     a.swap(b);
 }
 
+template<typename T> inline void Weak<T>::swap(Weak& other)
+{
+    std::swap(m_impl, other.m_impl);
+}
+
 template<typename T> inline Weak<T>& Weak<T>::operator=(const PassWeak<T>& o)
 {
     clear();
-    setSlot(o.leakHandle());
+    m_impl = o.leakImpl();
     return *this;
 }
 
+template<typename T> inline bool Weak<T>::operator!() const
+{
+    return !m_impl || !m_impl->jsValue() || m_impl->state() != WeakImpl::Live;
+}
+
+template<typename T> inline Weak<T>::operator UnspecifiedBoolType*() const
+{
+    return reinterpret_cast<UnspecifiedBoolType*>(!!*this);
+}
+
+template<typename T> inline PassWeak<T> Weak<T>::release()
+{
+    PassWeak<T> tmp = adoptWeak<T>(m_impl);
+    m_impl = 0;
+    return tmp;
+}
+
+template<typename T> inline void Weak<T>::clear()
+{
+    if (!m_impl)
+        return;
+    WeakHeap::deallocate(m_impl);
+    m_impl = 0;
+}
+    
+template<typename T> inline WeakImpl* Weak<T>::hashTableDeletedValue()
+{
+    return reinterpret_cast<WeakImpl*>(-1);
+}
+
 } // namespace JSC
 
 namespace WTF {
@@ -151,7 +171,7 @@ template<typename T> struct HashTraits<JSC::Weak<T> > : SimpleClassHashTraits<JS
     static PassOutType passOut(StorageType& value) { return value.release(); }
     static PassOutType passOut(EmptyValueType) { return PassOutType(); }
 
-    typedef typename StorageType::ExternalType PeekType;
+    typedef typename StorageType::GetType PeekType;
     static PeekType peek(const StorageType& value) { return value.get(); }
     static PeekType peek(EmptyValueType) { return PeekType(); }
 };
diff --git a/Source/JavaScriptCore/heap/WeakBlock.cpp b/Source/JavaScriptCore/heap/WeakBlock.cpp
new file mode 100644 (file)
index 0000000..f144f28
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+#include "WeakBlock.h"
+
+#include "Heap.h"
+#include "HeapRootVisitor.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+#include "Structure.h"
+
+namespace JSC {
+
+WeakBlock* WeakBlock::create()
+{
+    PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockSize, OSAllocator::JSGCHeapPages);
+    if (!static_cast<bool>(allocation))
+        CRASH();
+    return new (NotNull, allocation.base()) WeakBlock(allocation);
+}
+
+void WeakBlock::destroy(WeakBlock* block)
+{
+    block->m_allocation.deallocate();
+}
+
+WeakBlock::WeakBlock(PageAllocationAligned& allocation)
+    : HeapBlock(allocation)
+{
+    for (size_t i = 0; i < weakImplCount(); ++i) {
+        WeakImpl* weakImpl = &weakImpls()[i];
+        new (NotNull, weakImpl) WeakImpl;
+        addToFreeList(&m_sweepResult.freeList, weakImpl);
+    }
+
+    ASSERT(!m_sweepResult.isNull() && m_sweepResult.blockIsFree);
+}
+
+void WeakBlock::finalizeAll()
+{
+    for (size_t i = 0; i < weakImplCount(); ++i) {
+        WeakImpl* weakImpl = &weakImpls()[i];
+        if (weakImpl->state() >= WeakImpl::Finalized)
+            continue;
+        weakImpl->setState(WeakImpl::Dead);
+        finalize(weakImpl);
+    }
+}
+
+void WeakBlock::sweep()
+{
+    if (!m_sweepResult.isNull())
+        return;
+
+    SweepResult sweepResult;
+    for (size_t i = 0; i < weakImplCount(); ++i) {
+        WeakImpl* weakImpl = &weakImpls()[i];
+        if (weakImpl->state() == WeakImpl::Dead)
+            finalize(weakImpl);
+        if (weakImpl->state() == WeakImpl::Deallocated)
+            addToFreeList(&sweepResult.freeList, weakImpl);
+        else
+            sweepResult.blockIsFree = false;
+    }
+
+    m_sweepResult = sweepResult;
+    ASSERT(!m_sweepResult.isNull());
+}
+
+void WeakBlock::visitLiveWeakImpls(HeapRootVisitor& heapRootVisitor)
+{
+    // If a block is completely empty, a visit won't have any effect.
+    if (!m_sweepResult.isNull() && m_sweepResult.blockIsFree)
+        return;
+
+    SlotVisitor& visitor = heapRootVisitor.visitor();
+
+    for (size_t i = 0; i < weakImplCount(); ++i) {
+        WeakImpl* weakImpl = &weakImpls()[i];
+        if (weakImpl->state() != WeakImpl::Live)
+            continue;
+
+        const JSValue& jsValue = weakImpl->jsValue();
+        if (!jsValue || !jsValue.isCell())
+            continue;
+
+        JSCell* jsCell = jsValue.asCell();
+        if (Heap::isMarked(jsCell))
+            continue;
+
+        WeakHandleOwner* weakHandleOwner = weakImpl->weakHandleOwner();
+        if (!weakHandleOwner)
+            continue;
+
+        if (!weakHandleOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(jsValue)), weakImpl->context(), visitor))
+            continue;
+
+        heapRootVisitor.visit(&const_cast<JSValue&>(jsValue));
+    }
+}
+
+void WeakBlock::visitDeadWeakImpls(HeapRootVisitor&)
+{
+    // If a block is completely empty, a visit won't have any effect.
+    if (!m_sweepResult.isNull() && m_sweepResult.blockIsFree)
+        return;
+
+    for (size_t i = 0; i < weakImplCount(); ++i) {
+        WeakImpl* weakImpl = &weakImpls()[i];
+        if (weakImpl->state() > WeakImpl::Dead)
+            continue;
+
+        const JSValue& jsValue = weakImpl->jsValue();
+        if (!jsValue || !jsValue.isCell())
+            continue;
+
+        JSCell* jsCell = jsValue.asCell();
+        if (Heap::isMarked(jsCell))
+            continue;
+
+        weakImpl->setState(WeakImpl::Dead);
+    }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/heap/WeakBlock.h b/Source/JavaScriptCore/heap/WeakBlock.h
new file mode 100644 (file)
index 0000000..7f10962
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 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 WeakBlock_h
+#define WeakBlock_h
+
+#include "HeapBlock.h"
+#include "WeakHandleOwner.h"
+#include "WeakImpl.h"
+#include <wtf/DoublyLinkedList.h>
+#include <wtf/PageAllocationAligned.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+class HeapRootVisitor;
+class JSValue;
+class WeakHandleOwner;
+
+class WeakBlock : public HeapBlock {
+public:
+    static const size_t blockSize = 4 * KB;
+    static const size_t blockMask = ~(blockSize - 1);
+
+    struct FreeCell {
+        FreeCell* next;
+    };
+
+    struct SweepResult {
+        SweepResult();
+        bool isNull() const;
+
+        bool blockIsFree;
+        FreeCell* freeList;
+    };
+
+    static WeakBlock* create();
+    static void destroy(WeakBlock*);
+
+    static WeakBlock* blockFor(WeakImpl*);
+    static WeakImpl* asWeakImpl(FreeCell*);
+
+    void sweep();
+    const SweepResult& sweepResult();
+    SweepResult takeSweepResult();
+
+    void deallocate(WeakImpl*);
+
+    void visitLiveWeakImpls(HeapRootVisitor&);
+    void visitDeadWeakImpls(HeapRootVisitor&);
+
+    void finalizeAll();
+
+private:
+    static FreeCell* asFreeCell(WeakImpl*);
+
+    WeakBlock(PageAllocationAligned&);
+    WeakImpl* firstWeakImpl();
+    void finalize(WeakImpl*);
+    WeakImpl* weakImpls();
+    size_t weakImplCount();
+    void addToFreeList(FreeCell**, WeakImpl*);
+
+    SweepResult m_sweepResult;
+};
+
+inline WeakBlock::SweepResult::SweepResult()
+    : blockIsFree(true)
+    , freeList(0)
+{
+    ASSERT(isNull());
+}
+
+inline bool WeakBlock::SweepResult::isNull() const
+{
+    return blockIsFree && !freeList; // This state is impossible, so we can use it to mean null.
+}
+
+inline WeakBlock* WeakBlock::blockFor(WeakImpl* weakImpl)
+{
+    return reinterpret_cast<WeakBlock*>(reinterpret_cast<uintptr_t>(weakImpl) & blockMask);
+}
+
+inline WeakImpl* WeakBlock::asWeakImpl(FreeCell* freeCell)
+{
+    return reinterpret_cast<WeakImpl*>(freeCell);
+}
+
+inline WeakBlock::SweepResult WeakBlock::takeSweepResult()
+{
+    SweepResult tmp;
+    std::swap(tmp, m_sweepResult);
+    ASSERT(m_sweepResult.isNull());
+    return tmp;
+}
+
+inline const WeakBlock::SweepResult& WeakBlock::sweepResult()
+{
+    return m_sweepResult;
+}
+
+inline WeakBlock::FreeCell* WeakBlock::asFreeCell(WeakImpl* weakImpl)
+{
+    return reinterpret_cast<FreeCell*>(weakImpl);
+}
+
+inline void WeakBlock::deallocate(WeakImpl* weakImpl)
+{
+    weakImpl->setState(WeakImpl::Deallocated);
+}
+
+inline void WeakBlock::finalize(WeakImpl* weakImpl)
+{
+    ASSERT(weakImpl->state() == WeakImpl::Dead);
+    weakImpl->setState(WeakImpl::Finalized);
+    WeakHandleOwner* weakHandleOwner = weakImpl->weakHandleOwner();
+    if (!weakHandleOwner)
+        return;
+    weakHandleOwner->finalize(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(weakImpl->jsValue())), weakImpl->context());
+}
+
+inline WeakImpl* WeakBlock::weakImpls()
+{
+    return reinterpret_cast<WeakImpl*>(this) + ((sizeof(WeakBlock) + sizeof(WeakImpl) - 1) / sizeof(WeakImpl));
+}
+
+inline size_t WeakBlock::weakImplCount()
+{
+    return (blockSize / sizeof(WeakImpl)) - ((sizeof(WeakBlock) + sizeof(WeakImpl) - 1) / sizeof(WeakImpl));
+}
+
+inline void WeakBlock::addToFreeList(FreeCell** freeList, WeakImpl* weakImpl)
+{
+    ASSERT(weakImpl->state() == WeakImpl::Deallocated);
+    FreeCell* freeCell = asFreeCell(weakImpl);
+    ASSERT(!*freeList || ((char*)*freeList > (char*)this && (char*)*freeList < (char*)this + blockSize));
+    ASSERT((char*)freeCell > (char*)this && (char*)freeCell < (char*)this + blockSize);
+    freeCell->next = *freeList;
+    *freeList = freeCell;
+}
+
+} // namespace JSC
+
+#endif // WeakBlock_h
diff --git a/Source/JavaScriptCore/heap/WeakHandleOwner.cpp b/Source/JavaScriptCore/heap/WeakHandleOwner.cpp
new file mode 100644 (file)
index 0000000..67e1774
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+#include "WeakHandleOwner.h"
+
+namespace JSC {
+
+class SlotVisitor;
+template<typename T> class Handle;
+
+WeakHandleOwner::~WeakHandleOwner()
+{
+}
+
+bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&)
+{
+    return false;
+}
+
+void WeakHandleOwner::finalize(Handle<Unknown>, void*)
+{
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/heap/WeakHandleOwner.h b/Source/JavaScriptCore/heap/WeakHandleOwner.h
new file mode 100644 (file)
index 0000000..6304dd2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 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 WeakHandleOwner_h
+#define WeakHandleOwner_h
+
+#include "Handle.h"
+
+namespace JSC {
+
+class SlotVisitor;
+
+class JS_EXPORT_PRIVATE WeakHandleOwner {
+public:
+    virtual ~WeakHandleOwner();
+    virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&);
+    virtual void finalize(Handle<Unknown>, void* context);
+};
+
+} // namespace JSC
+
+#endif // WeakHandleOwner_h
diff --git a/Source/JavaScriptCore/heap/WeakHeap.cpp b/Source/JavaScriptCore/heap/WeakHeap.cpp
new file mode 100644 (file)
index 0000000..a7a3b41
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+#include "WeakHeap.h"
+
+#include "Heap.h"
+
+namespace JSC {
+
+WeakHeap::~WeakHeap()
+{
+    WeakBlock* next = 0;
+    for (WeakBlock* block = static_cast<WeakBlock*>(m_blocks.head()); block; block = next) {
+        next = static_cast<WeakBlock*>(block->next());
+        WeakBlock::destroy(block);
+    }
+    m_blocks.clear();
+}
+
+void WeakHeap::finalizeAll()
+{
+    for (WeakBlock* block = static_cast<WeakBlock*>(m_blocks.head()); block; block = static_cast<WeakBlock*>(block->next()))
+        block->finalizeAll();
+}
+
+void WeakHeap::visitLiveWeakImpls(HeapRootVisitor& visitor)
+{
+    for (WeakBlock* block = static_cast<WeakBlock*>(m_blocks.head()); block; block = static_cast<WeakBlock*>(block->next()))
+        block->visitLiveWeakImpls(visitor);
+}
+
+void WeakHeap::visitDeadWeakImpls(HeapRootVisitor& visitor)
+{
+    for (WeakBlock* block = static_cast<WeakBlock*>(m_blocks.head()); block; block = static_cast<WeakBlock*>(block->next()))
+        block->visitDeadWeakImpls(visitor);
+}
+
+void WeakHeap::sweep()
+{
+    WeakBlock* next;
+    for (WeakBlock* block = static_cast<WeakBlock*>(m_blocks.head()); block; block = next) {
+        next = static_cast<WeakBlock*>(block->next());
+
+        // If a block is completely empty, a new sweep won't have any effect.
+        if (!block->sweepResult().isNull() && block->sweepResult().blockIsFree)
+            continue;
+
+        block->takeSweepResult(); // Force a new sweep by discarding the last sweep.
+        block->sweep();
+    }
+}
+
+void WeakHeap::resetAllocator()
+{
+    m_allocator = 0;
+    m_nextAllocator = static_cast<WeakBlock*>(m_blocks.head());
+}
+
+WeakBlock::FreeCell* WeakHeap::findAllocator()
+{
+    if (WeakBlock::FreeCell* allocator = tryFindAllocator())
+        return allocator;
+
+    m_heap->addToWaterMark(WeakBlock::blockSize);
+
+    // addToWaterMark() may cause a GC, so try again.
+    if (WeakBlock::FreeCell* allocator = tryFindAllocator())
+        return allocator;
+
+    return addAllocator();
+}
+
+WeakBlock::FreeCell* WeakHeap::tryFindAllocator()
+{
+    while (m_nextAllocator) {
+        WeakBlock* block = m_nextAllocator;
+        m_nextAllocator = static_cast<WeakBlock*>(m_nextAllocator->next());
+
+        block->sweep();
+        WeakBlock::SweepResult sweepResult = block->takeSweepResult();
+        if (sweepResult.freeList)
+            return sweepResult.freeList;
+    }
+
+    return 0;
+}
+
+WeakBlock::FreeCell* WeakHeap::addAllocator()
+{
+    WeakBlock* block = WeakBlock::create();
+    m_blocks.append(block);
+    WeakBlock::SweepResult sweepResult = block->takeSweepResult();
+    ASSERT(!sweepResult.isNull() && sweepResult.freeList);
+    return sweepResult.freeList;
+}
+
+void WeakHeap::removeAllocator(WeakBlock* block)
+{
+    m_blocks.remove(block);
+    WeakBlock::destroy(block);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/heap/WeakHeap.h b/Source/JavaScriptCore/heap/WeakHeap.h
new file mode 100644 (file)
index 0000000..f434ade
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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 WeakHeap_h
+#define WeakHeap_h
+
+#include "WeakBlock.h"
+
+namespace JSC {
+
+class Heap;
+class WeakImpl;
+
+class WeakHeap {
+public:
+    WeakHeap(Heap*);
+    void finalizeAll();
+    ~WeakHeap();
+
+    WeakImpl* allocate(JSValue, WeakHandleOwner* = 0, void* context = 0);
+    static void deallocate(WeakImpl*);
+
+    void visitLiveWeakImpls(HeapRootVisitor&);
+    void visitDeadWeakImpls(HeapRootVisitor&);
+
+    void sweep();
+    void resetAllocator();
+
+private:
+    JS_EXPORT_PRIVATE WeakBlock::FreeCell* findAllocator();
+    WeakBlock::FreeCell* tryFindAllocator();
+    WeakBlock::FreeCell* addAllocator();
+    void removeAllocator(WeakBlock*);
+
+    WeakBlock::FreeCell* m_allocator;
+    WeakBlock* m_nextAllocator;
+    DoublyLinkedList<HeapBlock> m_blocks;
+    Heap* m_heap;
+};
+
+inline WeakHeap::WeakHeap(Heap* heap)
+    : m_allocator(0)
+    , m_nextAllocator(0)
+    , m_heap(heap)
+{
+}
+
+inline WeakImpl* WeakHeap::allocate(JSValue jsValue, WeakHandleOwner* weakHandleOwner, void* context)
+{
+    WeakBlock::FreeCell* allocator = m_allocator;
+    if (UNLIKELY(!allocator))
+        allocator = findAllocator();
+    m_allocator = allocator->next;
+
+    WeakImpl* weakImpl = WeakBlock::asWeakImpl(allocator);
+    return new (NotNull, weakImpl) WeakImpl(jsValue, weakHandleOwner, context);
+}
+
+inline void WeakHeap::deallocate(WeakImpl* weakImpl)
+{
+    WeakBlock::blockFor(weakImpl)->deallocate(weakImpl);
+}
+
+} // namespace JSC
+
+#endif // WeakHeap_h
diff --git a/Source/JavaScriptCore/heap/WeakImpl.h b/Source/JavaScriptCore/heap/WeakImpl.h
new file mode 100644 (file)
index 0000000..5467761
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 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 WeakImpl_h
+#define WeakImpl_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+class WeakHandleOwner;
+
+class WeakImpl {
+public:
+    enum State {
+        Live        = 0x0,
+        Dead        = 0x1,
+        Finalized   = 0x2,
+        Deallocated = 0x3
+    };
+
+    enum {
+        StateMask   = 0x3
+    };
+
+    WeakImpl();
+    WeakImpl(JSValue, WeakHandleOwner*, void* context);
+
+    State state();
+    void setState(State);
+
+    const JSValue& jsValue();
+    WeakHandleOwner* weakHandleOwner();
+    void* context();
+
+    static WeakImpl* asWeakImpl(JSValue*);
+
+private:
+    const JSValue m_jsValue;
+    WeakHandleOwner* m_weakHandleOwner;
+    void* m_context;
+};
+
+inline WeakImpl::WeakImpl()
+    : m_weakHandleOwner(0)
+    , m_context(0)
+{
+    setState(Deallocated);
+}
+
+inline WeakImpl::WeakImpl(JSValue jsValue, WeakHandleOwner* weakHandleOwner, void* context)
+    : m_jsValue(jsValue)
+    , m_weakHandleOwner(weakHandleOwner)
+    , m_context(context)
+{
+    ASSERT(state() == Live);
+}
+
+inline WeakImpl::State WeakImpl::state()
+{
+    return static_cast<State>(reinterpret_cast<uintptr_t>(m_weakHandleOwner) & StateMask);
+}
+
+inline void WeakImpl::setState(WeakImpl::State state)
+{
+    ASSERT(state >= this->state());
+    m_weakHandleOwner = reinterpret_cast<WeakHandleOwner*>((reinterpret_cast<uintptr_t>(m_weakHandleOwner) & ~StateMask) | state);
+}
+
+inline const JSValue& WeakImpl::jsValue()
+{
+    return m_jsValue;
+}
+
+inline WeakHandleOwner* WeakImpl::weakHandleOwner()
+{
+    return reinterpret_cast<WeakHandleOwner*>((reinterpret_cast<uintptr_t>(m_weakHandleOwner) & ~StateMask));
+}
+
+inline void* WeakImpl::context()
+{
+    return m_context;
+}
+
+inline WeakImpl* WeakImpl::asWeakImpl(JSValue* slot)
+{
+    return reinterpret_cast<WeakImpl*>(reinterpret_cast<char*>(slot) + OBJECT_OFFSETOF(WeakImpl, m_jsValue));
+}
+
+} // namespace JSC
+
+#endif // WeakImpl_h
index 82f6df7..3cb2c3a 100644 (file)
@@ -3575,7 +3575,7 @@ NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFu
 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic)
 {
     HostFunctionStubMap::AddResult entry = m_hostFunctionStubMap->add(function, PassWeak<NativeExecutable>());
-    if (!*entry.iterator->second) {
+    if (!entry.iterator->second) {
         MacroAssemblerCodeRef code;
         if (generator) {
             if (globalData->canUseJIT())
index e408cb7..232b474 100644 (file)
@@ -351,7 +351,7 @@ namespace JSC {
     template<typename To, typename From>
     inline To jsCast(From* from)
     {
-        ASSERT(from->inherits(&WTF::RemovePointer<To>::Type::s_info));
+        ASSERT(!from || from->inherits(&WTF::RemovePointer<To>::Type::s_info));
         return static_cast<To>(from);
     }
 
index 52eb1c7..875c4f1 100644 (file)
@@ -107,7 +107,7 @@ inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* s
         // There already is an entry! - we should only hit this when despecifying.
         ASSERT(result.iterator.get().second->m_specificValueInPrevious);
         ASSERT(!structure->m_specificValueInPrevious);
-        map()->set(result.iterator, structure);
+        map()->set(globalData, result.iterator.get().first, structure);
     }
 }
 
index 5179924..9949ba4 100644 (file)
@@ -34,6 +34,7 @@
 
 namespace JSC {
 
+class JSCell;
 class Structure;
 
 class StructureTransitionTable {
@@ -83,10 +84,10 @@ public:
             return;
         }
 
-        HandleSlot slot = this->slot();
-        if (!slot)
+        WeakImpl* impl = this->weakImpl();
+        if (!impl)
             return;
-        HandleHeap::heapFor(slot)->deallocate(slot);
+        WeakHeap::deallocate(impl);
     }
 
     inline void add(JSGlobalData&, Structure*);
@@ -105,18 +106,18 @@ private:
         return reinterpret_cast<TransitionMap*>(m_data);
     }
 
-    HandleSlot slot() const
+    WeakImpl* weakImpl() const
     {
         ASSERT(isUsingSingleSlot());
-        return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag);
+        return reinterpret_cast<WeakImpl*>(m_data & ~UsingSingleSlotFlag);
     }
 
     void setMap(TransitionMap* map)
     {
         ASSERT(isUsingSingleSlot());
         
-        if (HandleSlot slot = this->slot())
-            HandleHeap::heapFor(slot)->deallocate(slot);
+        if (WeakImpl* impl = this->weakImpl())
+            WeakHeap::deallocate(impl);
 
         // This implicitly clears the flag that indicates we're using a single transition
         m_data = reinterpret_cast<intptr_t>(map);
@@ -127,9 +128,9 @@ private:
     Structure* singleTransition() const
     {
         ASSERT(isUsingSingleSlot());
-        if (HandleSlot slot = this->slot()) {
-            if (*slot)
-                return reinterpret_cast<Structure*>(slot->asCell());
+        if (WeakImpl* impl = this->weakImpl()) {
+            if (impl->state() == WeakImpl::Live)
+                return reinterpret_cast<Structure*>(impl->jsValue().asCell());
         }
         return 0;
     }
@@ -137,14 +138,10 @@ private:
     void setSingleTransition(JSGlobalData& globalData, Structure* structure)
     {
         ASSERT(isUsingSingleSlot());
-        HandleSlot slot = this->slot();
-        if (!slot) {
-            slot = globalData.heap.handleHeap()->allocate();
-            HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0);
-            m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag;
-        }
-        HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure));
-        *slot = reinterpret_cast<JSCell*>(structure);
+        if (WeakImpl* impl = this->weakImpl())
+            WeakHeap::deallocate(impl);
+        WeakImpl* impl = globalData.heap.weakHeap()->allocate(reinterpret_cast<JSCell*>(structure));
+        m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag;
     }
 
     intptr_t m_data;
index f01a0c8..e964835 100644 (file)
@@ -51,7 +51,7 @@ class WeakGCMap : private WeakHandleOwner {
     WTF_MAKE_FAST_ALLOCATED;
     WTF_MAKE_NONCOPYABLE(WeakGCMap);
 
-    typedef HashMap<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType;
+    typedef HashMap<KeyType, WeakImpl*, HashArg, KeyTraitsArg> MapType;
     typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
     typedef typename MapType::iterator map_iterator;
 
@@ -64,8 +64,7 @@ public:
         {
         }
         
-        std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
-        std::pair<KeyType, HandleSlot> getSlot() const { return *m_iterator; }
+        std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_iterator->second->jsValue()))); }
         
         iterator& operator++() { ++m_iterator; return *this; }
         
@@ -90,7 +89,7 @@ public:
     {
         map_iterator end = m_map.end();
         for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
-            HandleHeap::heapFor(ptr->second)->deallocate(ptr->second);
+            WeakHeap::deallocate(ptr->second);
         m_map.clear();
     }
 
@@ -107,64 +106,42 @@ public:
     void remove(iterator iter)
     {
         ASSERT(iter.m_iterator != m_map.end());
-        HandleSlot slot = iter.m_iterator->second;
-        ASSERT(slot);
-        HandleHeap::heapFor(slot)->deallocate(slot);
+        WeakImpl* impl = iter.m_iterator->second;
+        ASSERT(impl);
+        WeakHeap::deallocate(impl);
         m_map.remove(iter.m_iterator);
     }
 
     ExternalType get(const KeyType& key) const
     {
-        return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
-    }
-
-    HandleSlot getSlot(const KeyType& key) const
-    {
-        return m_map.get(key);
+        return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_map.get(key)->jsValue()));
     }
 
     AddResult add(JSGlobalData& globalData, const KeyType& key, ExternalType value)
     {
         typename MapType::AddResult result = m_map.add(key, 0);
-        if (result.isNewEntry) {
-            HandleSlot slot = globalData.heap.handleHeap()->allocate();
-            result.iterator->second = slot;
-            HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key));
-            HandleHeap::heapFor(slot)->writeBarrier(slot, value);
-            *slot = value;
-        }
+        if (result.isNewEntry)
+            result.iterator->second = globalData.heap.weakHeap()->allocate(value, this, FinalizerCallback::finalizerContextFor(key));
+
         // WeakGCMap exposes a different iterator, so we need to wrap it and create our own AddResult.
         return AddResult(iterator(result.iterator), result.isNewEntry);
     }
-    
-    void set(iterator iter, ExternalType value)
-    {
-        HandleSlot slot = iter.m_iterator->second;
-        ASSERT(slot);
-        HandleHeap::heapFor(slot)->writeBarrier(slot, value);
-        *slot = value;
-    }
 
     void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
     {
         typename MapType::AddResult result = m_map.add(key, 0);
-        HandleSlot slot = result.iterator->second;
-        if (result.isNewEntry) {
-            slot = globalData.heap.handleHeap()->allocate();
-            HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
-            result.iterator->second = slot;
-        }
-        HandleHeap::heapFor(slot)->writeBarrier(slot, value);
-        *slot = value;
+        if (!result.isNewEntry)
+            WeakHeap::deallocate(result.iterator->second);
+        result.iterator->second = globalData.heap.weakHeap()->allocate(value, this, FinalizerCallback::finalizerContextFor(key));
     }
 
     ExternalType take(const KeyType& key)
     {
-        HandleSlot slot = m_map.take(key);
-        if (!slot)
+        WeakImpl* impl = m_map.take(key);
+        if (!impl)
             return HashTraits<ExternalType>::emptyValue();
-        ExternalType result = HandleTypes<MappedType>::getFromSlot(slot);
-        HandleHeap::heapFor(slot)->deallocate(slot);
+        ExternalType result = HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&impl->jsValue()));
+        WeakHeap::deallocate(impl);
         return result;
     }
 
@@ -181,9 +158,9 @@ public:
 private:
     virtual void finalize(Handle<Unknown> handle, void* context)
     {
-        HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
-        ASSERT(slot);
-        HandleHeap::heapFor(slot)->deallocate(slot);
+        WeakImpl* impl = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
+        ASSERT(impl);
+        WeakHeap::deallocate(impl);
     }
 
     MapType m_map;
index 4373ef0..30c12b9 100644 (file)
@@ -1,3 +1,32 @@
+2012-03-29  Geoffrey Garen  <ggaren@apple.com>
+
+        First step toward incremental Weak<T> finalization
+        https://bugs.webkit.org/show_bug.cgi?id=82670
+
+        Reviewed by Filip Pizlo.
+
+        Updated WebCore for Weak<T> API changes.
+
+        * bindings/js/DOMWrapperWorld.cpp:
+        (WebCore::JSStringOwner::finalize): We're not allowed to get() a dead Weak<T>
+        anymore, so use the debug-only was() helper function instead.
+
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::uncacheWrapper): Ditto.
+
+        * bindings/js/JSNodeCustom.h:
+        (WebCore::setInlineCachedWrapper):
+        (WebCore::clearInlineCachedWrapper): We're not allowed to get() a dead
+        Weak<T>, so I had to push down these ASSERTs into ScriptWrappable.
+
+        * bindings/js/JSNodeFilterCondition.cpp:
+        (WebCore::JSNodeFilterCondition::acceptNode): Updated for non-Handle-ness
+        of Weak<T>.
+
+        * bindings/js/ScriptWrappable.h:
+        (WebCore::ScriptWrappable::setWrapper):
+        (WebCore::ScriptWrappable::clearWrapper): Use was(), as above.
+
 2012-04-03  Luke Macpherson  <macpherson@chromium.org>
 
         Don't parse "show" and "hide" as valid values for display property.
index 812549b..d082242 100644 (file)
@@ -34,7 +34,7 @@ void JSStringOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
 {
     JSString* jsString = static_cast<JSString*>(handle.get().asCell());
     StringImpl* stringImpl = static_cast<StringImpl*>(context);
-    ASSERT_UNUSED(jsString, m_world->m_stringCache.find(stringImpl)->second.get() == jsString);
+    ASSERT_UNUSED(jsString, m_world->m_stringCache.find(stringImpl)->second.was(jsString));
     m_world->m_stringCache.remove(stringImpl);
 }
 
index 7eebc77..98746e9 100644 (file)
@@ -150,7 +150,7 @@ enum ParameterDefaultPolicy {
     {
         if (clearInlineCachedWrapper(world, domObject, wrapper))
             return;
-        ASSERT(world->m_wrappers.find(domObject)->second.get() == wrapper);
+        ASSERT(world->m_wrappers.find(domObject)->second.was(wrapper));
         world->m_wrappers.remove(domObject);
     }
     
index 7688eea..518b21d 100644 (file)
@@ -42,7 +42,6 @@ inline bool setInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrap
 {
     if (!world->isNormal())
         return false;
-    ASSERT(!node->wrapper());
     node->setWrapper(*world->globalData(), wrapper, wrapperOwner(world, node), wrapperContext(world, node));
     return true;
 }
@@ -51,8 +50,7 @@ inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWr
 {
     if (!world->isNormal())
         return false;
-    ASSERT_UNUSED(wrapper, node->wrapper() == wrapper);
-    node->clearWrapper();
+    node->clearWrapper(wrapper);
     return true;
 }
 
index 91b9156..ce24752 100644 (file)
@@ -42,7 +42,7 @@ short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode)
 {
     JSLock lock(SilenceAssertionsOnly);
 
-    if (!m_filter.isObject())
+    if (!m_filter || !m_filter->isObject())
         return NodeFilter::FILTER_ACCEPT;
 
    // The exec argument here should only be null if this was called from a
index 92d05e8..73b2d6f 100644 (file)
@@ -45,11 +45,13 @@ public:
 
     void setWrapper(JSC::JSGlobalData& globalData, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context)
     {
+        ASSERT(!m_wrapper);
         m_wrapper = JSC::PassWeak<JSDOMWrapper>(globalData, wrapper, wrapperOwner, context);
     }
 
-    void clearWrapper()
+    void clearWrapper(JSDOMWrapper* wrapper)
     {
+        ASSERT_UNUSED(wrapper, m_wrapper.was(wrapper));
         m_wrapper.clear();
     }
 
index 45831cb..6982213 100644 (file)
@@ -1,3 +1,15 @@
+2012-03-29  Geoffrey Garen  <ggaren@apple.com>
+
+        First step toward incremental Weak<T> finalization
+        https://bugs.webkit.org/show_bug.cgi?id=82670
+
+        Reviewed by Filip Pizlo.
+
+        Updated for API change.
+
+        * WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
+        (WebKit::NPRuntimeObjectMap::finalize):
+
 2012-04-03  Keishi Hattori  <keishi@webkit.org>
 
         Disable ENABLE_DATALIST for now
index 01e73f9..b4f0381 100644 (file)
@@ -292,7 +292,7 @@ void NPRuntimeObjectMap::finalize(JSC::Handle<JSC::Unknown> handle, void* contex
 {
     HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator found = m_jsNPObjects.find(static_cast<NPObject*>(context));
     ASSERT(found != m_jsNPObjects.end());
-    ASSERT_UNUSED(handle, asObject(handle.get()) == found->second);
+    ASSERT_UNUSED(handle, asObject(handle.get()) == found->second.get());
     JSNPObject* object = found->second.get();
     m_jsNPObjects.remove(found);
     addToInvalidationQueue(object->leakNPObject());
index 6983984..e62d539 100644 (file)
@@ -35,6 +35,8 @@
 #include <WebCore/HTTPHeaderMap.h>
 #include <WebCore/IntRect.h>
 #include <WebCore/KURL.h>
+#include <runtime/JSObject.h>
+#include <runtime/ScopeChain.h>
 #include <utility>
 #include <wtf/text/CString.h>
 
index b215271..8339ad4 100644 (file)
@@ -28,6 +28,8 @@
 
 #if ENABLE(PLUGIN_PROCESS)
 
+#include <runtime/JSObject.h>
+#include <runtime/ScopeChain.h>
 #include "NPRemoteObjectMap.h"
 #include "NPRuntimeObjectMap.h"
 #include "PluginProcessConnectionManager.h"