From 762158113e5748d19474443b6c8e1bb1c848b638 Mon Sep 17 00:00:00 2001 From: "ggaren@apple.com" Date: Wed, 4 Apr 2012 05:28:13 +0000 Subject: [PATCH] First step toward incremental Weak finalization https://bugs.webkit.org/show_bug.cgi?id=82670 Reviewed by Filip Pizlo. Source/JavaScriptCore: This patch implements a Weak heap that is compatible with incremental finalization, while making as few behavior changes as possible. The behavior changes it makes are: (*) Weak'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 is no longer a subclass of Handle. (*) 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 Weaks 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 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, 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 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 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 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 API changes. * bindings/js/DOMWrapperWorld.cpp: (WebCore::JSStringOwner::finalize): We're not allowed to get() a dead Weak 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, so I had to push down these ASSERTs into ScriptWrappable. * bindings/js/JSNodeFilterCondition.cpp: (WebCore::JSNodeFilterCondition::acceptNode): Updated for non-Handle-ness of Weak. * 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 --- Source/JavaScriptCore/API/JSCallbackObject.cpp | 3 +- .../JavaScriptCore/API/JSCallbackObjectFunctions.h | 13 +- Source/JavaScriptCore/CMakeLists.txt | 7 +- Source/JavaScriptCore/ChangeLog | 169 ++++++++++++++++++++ Source/JavaScriptCore/GNUmakefile.list.am | 3 + Source/JavaScriptCore/JavaScriptCore.gypi | 3 + .../JavaScriptCore/JavaScriptCore.def | 29 ++-- .../JavaScriptCore/JavaScriptCore.vcproj | 28 ++++ .../JavaScriptCore.xcodeproj/project.pbxproj | 28 ++++ Source/JavaScriptCore/Target.pri | 3 + Source/JavaScriptCore/heap/Handle.h | 4 +- Source/JavaScriptCore/heap/HandleHeap.cpp | 96 ------------ Source/JavaScriptCore/heap/HandleHeap.h | 101 ------------ Source/JavaScriptCore/heap/Heap.cpp | 37 +++-- Source/JavaScriptCore/heap/Heap.h | 16 +- Source/JavaScriptCore/heap/MarkedSpace.cpp | 2 - Source/JavaScriptCore/heap/MarkedSpace.h | 9 +- Source/JavaScriptCore/heap/PassWeak.h | 173 +++++++++++++++----- Source/JavaScriptCore/heap/Strong.h | 8 + Source/JavaScriptCore/heap/Weak.h | 174 ++++++++++++--------- Source/JavaScriptCore/heap/WeakBlock.cpp | 148 ++++++++++++++++++ Source/JavaScriptCore/heap/WeakBlock.h | 166 ++++++++++++++++++++ Source/JavaScriptCore/heap/WeakHandleOwner.cpp | 47 ++++++ Source/JavaScriptCore/heap/WeakHandleOwner.h | 44 ++++++ Source/JavaScriptCore/heap/WeakHeap.cpp | 126 +++++++++++++++ Source/JavaScriptCore/heap/WeakHeap.h | 88 +++++++++++ Source/JavaScriptCore/heap/WeakImpl.h | 114 ++++++++++++++ Source/JavaScriptCore/jit/JITStubs.cpp | 2 +- Source/JavaScriptCore/runtime/JSCell.h | 2 +- Source/JavaScriptCore/runtime/Structure.cpp | 2 +- .../runtime/StructureTransitionTable.h | 33 ++-- Source/JavaScriptCore/runtime/WeakGCMap.h | 63 +++----- Source/WebCore/ChangeLog | 29 ++++ Source/WebCore/bindings/js/DOMWrapperWorld.cpp | 2 +- Source/WebCore/bindings/js/JSDOMBinding.h | 2 +- Source/WebCore/bindings/js/JSNodeCustom.h | 4 +- .../WebCore/bindings/js/JSNodeFilterCondition.cpp | 2 +- Source/WebCore/bindings/js/ScriptWrappable.h | 4 +- Source/WebKit2/ChangeLog | 12 ++ .../Plugins/Netscape/NPRuntimeObjectMap.cpp | 2 +- .../WebProcess/Plugins/Netscape/NetscapePlugin.cpp | 2 + .../WebProcess/Plugins/PluginProcessConnection.cpp | 2 + 42 files changed, 1364 insertions(+), 438 deletions(-) create mode 100644 Source/JavaScriptCore/heap/WeakBlock.cpp create mode 100644 Source/JavaScriptCore/heap/WeakBlock.h create mode 100644 Source/JavaScriptCore/heap/WeakHandleOwner.cpp create mode 100644 Source/JavaScriptCore/heap/WeakHandleOwner.h create mode 100644 Source/JavaScriptCore/heap/WeakHeap.cpp create mode 100644 Source/JavaScriptCore/heap/WeakHeap.h create mode 100644 Source/JavaScriptCore/heap/WeakImpl.h diff --git a/Source/JavaScriptCore/API/JSCallbackObject.cpp b/Source/JavaScriptCore/API/JSCallbackObject.cpp index ef9cb92..5dba9a0 100644 --- a/Source/JavaScriptCore/API/JSCallbackObject.cpp +++ b/Source/JavaScriptCore/API/JSCallbackObject.cpp @@ -65,8 +65,7 @@ void JSCallbackObjectData::finalize(Handle 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 diff --git a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h index e6bb884..c1e8246 100644 --- a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h +++ b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h @@ -102,14 +102,11 @@ void JSCallbackObject::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; + } } } diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index f6bcc02..223ceb9 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -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 diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 7a1bb83764..6b86e73 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,172 @@ +2012-03-29 Geoffrey Garen + + First step toward incremental Weak finalization + https://bugs.webkit.org/show_bug.cgi?id=82670 + + Reviewed by Filip Pizlo. + + This patch implements a Weak heap that is compatible with incremental + finalization, while making as few behavior changes as possible. The behavior + changes it makes are: + + (*) Weak'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 is no longer a subclass of Handle. + + (*) 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 Weaks 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 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, 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 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 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 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 Disable ENABLE_DATALIST for now diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index 012a83c..7d0325f 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -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 \ diff --git a/Source/JavaScriptCore/JavaScriptCore.gypi b/Source/JavaScriptCore/JavaScriptCore.gypi index c07b391..ec8a268 100644 --- a/Source/JavaScriptCore/JavaScriptCore.gypi +++ b/Source/JavaScriptCore/JavaScriptCore.gypi @@ -217,6 +217,9 @@ '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', diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 7ffa6c1..8603a80 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -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 diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 6b359f4..2fcdc38f 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -2130,6 +2130,34 @@ > + + + + + + + + + + + + + + diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index d663889..125e43b 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -323,7 +323,14 @@ 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, ); }; }; @@ -943,7 +950,14 @@ 14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = ""; }; 14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSActivation.cpp; sourceTree = ""; }; 14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObject.cpp; sourceTree = ""; }; + 14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakBlock.cpp; sourceTree = ""; }; + 14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakBlock.h; sourceTree = ""; }; + 14E84F9B14EE1ACC00D6D5D4 /* WeakHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakHeap.cpp; sourceTree = ""; }; + 14E84F9C14EE1ACC00D6D5D4 /* WeakHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakHeap.h; sourceTree = ""; }; + 14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakImpl.h; sourceTree = ""; }; 14F252560D08DD8D004ECFFF /* JSVariableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVariableObject.h; sourceTree = ""; }; + 14F7256314EE265E00B1652B /* WeakHandleOwner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakHandleOwner.cpp; sourceTree = ""; }; + 14F7256414EE265E00B1652B /* WeakHandleOwner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakHandleOwner.h; sourceTree = ""; }; 14F97446138C853E00DA1C67 /* HeapRootVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapRootVisitor.h; sourceTree = ""; }; 1C9051420BA9E8A70081E9D0 /* Version.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = ""; }; 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = JavaScriptCore.xcconfig; sourceTree = ""; }; @@ -1586,6 +1600,13 @@ 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 */, @@ -2523,6 +2544,10 @@ 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 */, @@ -3079,6 +3104,9 @@ 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 */, diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index 2bc8089..2797e10 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -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 \ diff --git a/Source/JavaScriptCore/heap/Handle.h b/Source/JavaScriptCore/heap/Handle.h index 6f46774..13312c8 100644 --- a/Source/JavaScriptCore/heap/Handle.h +++ b/Source/JavaScriptCore/heap/Handle.h @@ -59,6 +59,8 @@ public: typedef JSValue (HandleBase::*UnspecifiedBoolType); operator UnspecifiedBoolType*() const { return (m_slot && *m_slot) ? reinterpret_cast(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 wrapSlot(HandleSlot slot) { diff --git a/Source/JavaScriptCore/heap/HandleHeap.cpp b/Source/JavaScriptCore/heap/HandleHeap.cpp index 2402f7e..38b3371 100644 --- a/Source/JavaScriptCore/heap/HandleHeap.cpp +++ b/Source/JavaScriptCore/heap/HandleHeap.cpp @@ -31,19 +31,6 @@ namespace JSC { -WeakHandleOwner::~WeakHandleOwner() -{ -} - -bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle, void*, SlotVisitor&) -{ - return false; -} - -void WeakHandleOwner::finalize(Handle, 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::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::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::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 diff --git a/Source/JavaScriptCore/heap/HandleHeap.h b/Source/JavaScriptCore/heap/HandleHeap.h index c9ee11b..c2cba20 100644 --- a/Source/JavaScriptCore/heap/HandleHeap.h +++ b/Source/JavaScriptCore/heap/HandleHeap.h @@ -40,13 +40,6 @@ class JSGlobalData; class JSValue; class SlotVisitor; -class JS_EXPORT_PRIVATE WeakHandleOwner { -public: - virtual ~WeakHandleOwner(); - virtual bool isReachableFromOpaqueRoots(Handle, void* context, SlotVisitor&); - virtual void finalize(Handle, 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 void forEachStrongHandle(Functor&, const HashCountedSet& 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 m_blockStack; SentinelLinkedList m_strongList; - SentinelLinkedList m_weakList; SentinelLinkedList m_immediateList; SinglyLinkedList 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::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(-1); -} - template void HandleHeap::forEachStrongHandle(Functor& functor, const HashCountedSet& skipSet) { Node* end = m_strongList.end(); diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index c54ba77..a41764f 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -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 activityCallback) @@ -924,15 +927,15 @@ void Heap::releaseFreeBlocks() void Heap::addFinalizer(JSCell* cell, Finalizer finalizer) { - Weak weak(*globalData(), cell, &m_finalizerOwner, reinterpret_cast(finalizer)); - weak.leakHandle(); // Balanced by FinalizerOwner::finalize(). + weakHeap()->allocate(cell, &m_finalizerOwner, reinterpret_cast(finalizer)); // Balanced by FinalizerOwner::finalize(). } void Heap::FinalizerOwner::finalize(Handle handle, void* context) { - Weak weak(Weak::Adopt, handle); + HandleSlot slot = handle.slot(); Finalizer finalizer = reinterpret_cast(context); - finalizer(weak.get()); + finalizer(slot->asCell()); + WeakHeap::deallocate(WeakImpl::asWeakImpl(slot)); } void Heap::addFunctionExecutable(FunctionExecutable* executable) diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index c78c856..2c36c1f 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -30,6 +30,8 @@ #include "MarkedBlockSet.h" #include "MarkedSpace.h" #include "SlotVisitor.h" +#include "WeakHandleOwner.h" +#include "WeakHeap.h" #include "WriteBarrierSupport.h" #include #include @@ -136,11 +138,14 @@ namespace JSC { template typename Functor::ReturnType forEachProtectedCell(Functor&); template typename Functor::ReturnType forEachProtectedCell(); + WeakHeap* weakHeap() { return &m_weakHeap; } HandleHeap* handleHeap() { return &m_handleHeap; } HandleStack* handleStack() { return &m_handleStack; } void getConservativeRegisterRoots(HashSet& 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* > m_tempSortingVectors; HashSet* 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) diff --git a/Source/JavaScriptCore/heap/MarkedSpace.cpp b/Source/JavaScriptCore/heap/MarkedSpace.cpp index bf83901..a7d9da2 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.cpp +++ b/Source/JavaScriptCore/heap/MarkedSpace.cpp @@ -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(); diff --git a/Source/JavaScriptCore/heap/MarkedSpace.h b/Source/JavaScriptCore/heap/MarkedSpace.h index b553eb1..2ac053e 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.h +++ b/Source/JavaScriptCore/heap/MarkedSpace.h @@ -66,7 +66,7 @@ public: void canonicalizeCellLivenessData(); size_t waterMark(); - size_t nurseryWaterMark(); + void addToWaterMark(size_t); typedef HashSet::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 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(); } diff --git a/Source/JavaScriptCore/heap/PassWeak.h b/Source/JavaScriptCore/heap/PassWeak.h index 0d86e6c..557854b 100644 --- a/Source/JavaScriptCore/heap/PassWeak.h +++ b/Source/JavaScriptCore/heap/PassWeak.h @@ -26,8 +26,8 @@ #ifndef PassWeak_h #define PassWeak_h +#include "JSCell.h" #include -#include "Handle.h" #include #include @@ -35,61 +35,164 @@ namespace JSC { template class Weak; template class PassWeak; -template PassWeak adoptWeak(HandleSlot); +template PassWeak adoptWeak(WeakImpl*); -template class PassWeak : public Handle { - using Handle::slot; - using Handle::setSlot; +template class WeakImplAccessor { +public: + typedef T* GetType; + + T* operator->() const; + T& operator*() const; + GetType get() const; + +#if !ASSERT_DISABLED + bool was(GetType) const; +#endif +}; +template class WeakImplAccessor { public: - typedef typename Handle::ExternalType ExternalType; + typedef JSValue GetType; - PassWeak() : Handle() { } - PassWeak(std::nullptr_t) : Handle() { } + const JSValue* operator->() const; + const JSValue& operator*() const; + GetType get() const; +}; + +template class PassWeak : public WeakImplAccessor, T> { +public: + friend class WeakImplAccessor, T>; + typedef typename WeakImplAccessor, T>::GetType GetType; - PassWeak(JSGlobalData& globalData, ExternalType externalType = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0) - : Handle(globalData.heap.handleHeap()->allocate()) - { - HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context); - JSValue value = HandleTypes::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(o.leakHandle()) { } - template PassWeak(const PassWeak& o) : Handle(o.leakHandle()) { } + PassWeak(const PassWeak&); + template PassWeak(const PassWeak&); - ~PassWeak() - { - if (!slot()) - return; - HandleHeap::heapFor(slot())->deallocate(slot()); - setSlot(0); - } + ~PassWeak(); - ExternalType get() const { return HandleTypes::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(HandleSlot); + friend PassWeak adoptWeak(WeakImpl*); + explicit PassWeak(WeakImpl*); - explicit PassWeak(HandleSlot slot) : Handle(slot) { } + WeakImpl* m_impl; }; -template inline HandleSlot PassWeak::leakHandle() const +template inline T* WeakImplAccessor::operator->() const +{ + ASSERT(static_cast(this)->m_impl && static_cast(this)->m_impl->state() == WeakImpl::Live); + return jsCast(static_cast(this)->m_impl->jsValue().asCell()); +} + +template inline T& WeakImplAccessor::operator*() const +{ + ASSERT(static_cast(this)->m_impl && static_cast(this)->m_impl->state() == WeakImpl::Live); + return *jsCast(static_cast(this)->m_impl->jsValue().asCell()); +} + +template inline typename WeakImplAccessor::GetType WeakImplAccessor::get() const +{ + if (!static_cast(this)->m_impl || static_cast(this)->m_impl->state() != WeakImpl::Live) + return GetType(); + return jsCast(static_cast(this)->m_impl->jsValue().asCell()); +} + +#if !ASSERT_DISABLED +template inline bool WeakImplAccessor::was(typename WeakImplAccessor::GetType other) const +{ + return jsCast(static_cast(this)->m_impl->jsValue().asCell()) == other; +} +#endif + +template inline const JSValue* WeakImplAccessor::operator->() const +{ + ASSERT(static_cast(this)->m_impl && static_cast(this)->m_impl->state() == WeakImpl::Live); + return &static_cast(this)->m_impl->jsValue(); +} + +template inline const JSValue& WeakImplAccessor::operator*() const +{ + ASSERT(static_cast(this)->m_impl && static_cast(this)->m_impl->state() == WeakImpl::Live); + return static_cast(this)->m_impl->jsValue(); +} + +template inline typename WeakImplAccessor::GetType WeakImplAccessor::get() const +{ + if (!static_cast(this)->m_impl || static_cast(this)->m_impl->state() != WeakImpl::Live) + return GetType(); + return static_cast(this)->m_impl->jsValue(); +} + +template inline PassWeak::PassWeak() + : m_impl(0) +{ +} + +template inline PassWeak::PassWeak(std::nullptr_t) + : m_impl(0) +{ +} + +template inline PassWeak::PassWeak(JSGlobalData& globalData, typename PassWeak::GetType getType, WeakHandleOwner* weakOwner, void* context) + : m_impl(globalData.heap.weakHeap()->allocate(getType, weakOwner, context)) +{ +} + +template inline PassWeak::PassWeak(const PassWeak& o) + : m_impl(o.leakImpl()) +{ +} + +template template inline PassWeak::PassWeak(const PassWeak& o) + : m_impl(o.leakImpl()) +{ +} + +template inline PassWeak::~PassWeak() +{ + if (!m_impl) + return; + WeakHeap::deallocate(m_impl); +} + +template inline bool PassWeak::operator!() const +{ + return !m_impl || m_impl->state() != WeakImpl::Live || !m_impl->jsValue(); +} + +template inline PassWeak::operator UnspecifiedBoolType*() const +{ + return reinterpret_cast(!!*this); +} + +template inline PassWeak::PassWeak(WeakImpl* impl) +: m_impl(impl) +{ +} + +template inline WeakImpl* PassWeak::leakImpl() const { - HandleSlot slot = this->slot(); - const_cast*>(this)->setSlot(0); - return slot; + WeakImpl* tmp = 0; + std::swap(tmp, const_cast(m_impl)); + return tmp; } -template PassWeak adoptWeak(HandleSlot slot) +template PassWeak inline adoptWeak(WeakImpl* impl) { - return PassWeak(slot); + return PassWeak(impl); } template inline bool operator==(const PassWeak& a, const PassWeak& b) diff --git a/Source/JavaScriptCore/heap/Strong.h b/Source/JavaScriptCore/heap/Strong.h index d2f2a22..9874ab8 100644 --- a/Source/JavaScriptCore/heap/Strong.h +++ b/Source/JavaScriptCore/heap/Strong.h @@ -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(1) : 0; } + void swap(Strong& other) { Handle::swap(other); } + ExternalType get() const { return HandleTypes::getFromSlot(this->slot()); } + void set(JSGlobalData&, ExternalType); template Strong& operator=(const Strong& other) diff --git a/Source/JavaScriptCore/heap/Weak.h b/Source/JavaScriptCore/heap/Weak.h index 8291e44..b05a484 100644 --- a/Source/JavaScriptCore/heap/Weak.h +++ b/Source/JavaScriptCore/heap/Weak.h @@ -27,109 +27,129 @@ #define Weak_h #include -#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 class Weak : public Handle { +template class Weak : public WeakImplAccessor, T> { WTF_MAKE_NONCOPYABLE(Weak); - - using Handle::slot; - using Handle::setSlot; - public: - typedef typename Handle::ExternalType ExternalType; - - Weak() - : Handle() - { - } - - Weak(std::nullptr_t) - : Handle() - { - } - - Weak(JSGlobalData& globalData, ExternalType externalType = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0) - : Handle(globalData.heap.handleHeap()->allocate()) - { - HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context); - JSValue value = HandleTypes::toJSValue(externalType); - HandleHeap::heapFor(slot())->writeBarrier(slot(), value); - *slot() = value; - } - - enum AdoptTag { Adopt }; - template Weak(AdoptTag, Handle handle) - : Handle(handle.slot()) - { - validateCell(get()); - } + friend class WeakImplAccessor, T>; + typedef typename WeakImplAccessor, 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(hashTableDeletedValue()) - { - } - - template Weak(const PassWeak& other) - : Handle(other.leakHandle()) - { - } - - ~Weak() - { - clear(); - } - - void swap(Weak& other) - { - Handle::swap(other); - } + bool isHashTableDeletedValue() const; + Weak(HashTableDeletedValueTag); - Weak& operator=(const PassWeak&); + template Weak(const PassWeak&); - ExternalType get() const { return HandleTypes::getFromSlot(slot()); } - - PassWeak release() { PassWeak tmp = adoptWeak(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&); - 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 release(); + void clear(); + private: - static HandleSlot hashTableDeletedValue() { return reinterpret_cast(-1); } + static WeakImpl* hashTableDeletedValue(); + + WeakImpl* m_impl; }; +template inline Weak::Weak() + : m_impl(0) +{ +} + +template inline Weak::Weak(std::nullptr_t) + : m_impl(0) +{ +} + +template inline Weak::Weak(JSGlobalData& globalData, typename Weak::GetType getType, WeakHandleOwner* weakOwner, void* context) + : m_impl(globalData.heap.weakHeap()->allocate(getType, weakOwner, context)) +{ +} + +template inline bool Weak::isHashTableDeletedValue() const +{ + return m_impl == hashTableDeletedValue(); +} + +template inline Weak::Weak(typename Weak::HashTableDeletedValueTag) + : m_impl(hashTableDeletedValue()) +{ +} + +template template inline Weak::Weak(const PassWeak& other) + : m_impl(other.leakImpl()) +{ +} + +template inline Weak::~Weak() +{ + clear(); +} + template inline void swap(Weak& a, Weak& b) { a.swap(b); } +template inline void Weak::swap(Weak& other) +{ + std::swap(m_impl, other.m_impl); +} + template inline Weak& Weak::operator=(const PassWeak& o) { clear(); - setSlot(o.leakHandle()); + m_impl = o.leakImpl(); return *this; } +template inline bool Weak::operator!() const +{ + return !m_impl || !m_impl->jsValue() || m_impl->state() != WeakImpl::Live; +} + +template inline Weak::operator UnspecifiedBoolType*() const +{ + return reinterpret_cast(!!*this); +} + +template inline PassWeak Weak::release() +{ + PassWeak tmp = adoptWeak(m_impl); + m_impl = 0; + return tmp; +} + +template inline void Weak::clear() +{ + if (!m_impl) + return; + WeakHeap::deallocate(m_impl); + m_impl = 0; +} + +template inline WeakImpl* Weak::hashTableDeletedValue() +{ + return reinterpret_cast(-1); +} + } // namespace JSC namespace WTF { @@ -151,7 +171,7 @@ template struct HashTraits > : SimpleClassHashTraits(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::wrapSlot(&const_cast(jsValue)), weakImpl->context(), visitor)) + continue; + + heapRootVisitor.visit(&const_cast(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 index 0000000..7f10962 --- /dev/null +++ b/Source/JavaScriptCore/heap/WeakBlock.h @@ -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 +#include +#include + +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(reinterpret_cast(weakImpl) & blockMask); +} + +inline WeakImpl* WeakBlock::asWeakImpl(FreeCell* freeCell) +{ + return reinterpret_cast(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(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::wrapSlot(&const_cast(weakImpl->jsValue())), weakImpl->context()); +} + +inline WeakImpl* WeakBlock::weakImpls() +{ + return reinterpret_cast(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 index 0000000..67e1774 --- /dev/null +++ b/Source/JavaScriptCore/heap/WeakHandleOwner.cpp @@ -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 class Handle; + +WeakHandleOwner::~WeakHandleOwner() +{ +} + +bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle, void*, SlotVisitor&) +{ + return false; +} + +void WeakHandleOwner::finalize(Handle, void*) +{ +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/heap/WeakHandleOwner.h b/Source/JavaScriptCore/heap/WeakHandleOwner.h new file mode 100644 index 0000000..6304dd2 --- /dev/null +++ b/Source/JavaScriptCore/heap/WeakHandleOwner.h @@ -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, void* context, SlotVisitor&); + virtual void finalize(Handle, 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 index 0000000..a7a3b41 --- /dev/null +++ b/Source/JavaScriptCore/heap/WeakHeap.cpp @@ -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(m_blocks.head()); block; block = next) { + next = static_cast(block->next()); + WeakBlock::destroy(block); + } + m_blocks.clear(); +} + +void WeakHeap::finalizeAll() +{ + for (WeakBlock* block = static_cast(m_blocks.head()); block; block = static_cast(block->next())) + block->finalizeAll(); +} + +void WeakHeap::visitLiveWeakImpls(HeapRootVisitor& visitor) +{ + for (WeakBlock* block = static_cast(m_blocks.head()); block; block = static_cast(block->next())) + block->visitLiveWeakImpls(visitor); +} + +void WeakHeap::visitDeadWeakImpls(HeapRootVisitor& visitor) +{ + for (WeakBlock* block = static_cast(m_blocks.head()); block; block = static_cast(block->next())) + block->visitDeadWeakImpls(visitor); +} + +void WeakHeap::sweep() +{ + WeakBlock* next; + for (WeakBlock* block = static_cast(m_blocks.head()); block; block = next) { + next = static_cast(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(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(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 index 0000000..f434ade --- /dev/null +++ b/Source/JavaScriptCore/heap/WeakHeap.h @@ -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 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 index 0000000..5467761 --- /dev/null +++ b/Source/JavaScriptCore/heap/WeakImpl.h @@ -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(reinterpret_cast(m_weakHandleOwner) & StateMask); +} + +inline void WeakImpl::setState(WeakImpl::State state) +{ + ASSERT(state >= this->state()); + m_weakHandleOwner = reinterpret_cast((reinterpret_cast(m_weakHandleOwner) & ~StateMask) | state); +} + +inline const JSValue& WeakImpl::jsValue() +{ + return m_jsValue; +} + +inline WeakHandleOwner* WeakImpl::weakHandleOwner() +{ + return reinterpret_cast((reinterpret_cast(m_weakHandleOwner) & ~StateMask)); +} + +inline void* WeakImpl::context() +{ + return m_context; +} + +inline WeakImpl* WeakImpl::asWeakImpl(JSValue* slot) +{ + return reinterpret_cast(reinterpret_cast(slot) + OBJECT_OFFSETOF(WeakImpl, m_jsValue)); +} + +} // namespace JSC + +#endif // WeakImpl_h diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 82f6df7..3cb2c3a 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -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()); - if (!*entry.iterator->second) { + if (!entry.iterator->second) { MacroAssemblerCodeRef code; if (generator) { if (globalData->canUseJIT()) diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index e408cb7..232b474 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -351,7 +351,7 @@ namespace JSC { template inline To jsCast(From* from) { - ASSERT(from->inherits(&WTF::RemovePointer::Type::s_info)); + ASSERT(!from || from->inherits(&WTF::RemovePointer::Type::s_info)); return static_cast(from); } diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index 52eb1c7..875c4f1 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -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); } } diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 5179924..9949ba4 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -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(m_data); } - HandleSlot slot() const + WeakImpl* weakImpl() const { ASSERT(isUsingSingleSlot()); - return reinterpret_cast(m_data & ~UsingSingleSlotFlag); + return reinterpret_cast(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(map); @@ -127,9 +128,9 @@ private: Structure* singleTransition() const { ASSERT(isUsingSingleSlot()); - if (HandleSlot slot = this->slot()) { - if (*slot) - return reinterpret_cast(slot->asCell()); + if (WeakImpl* impl = this->weakImpl()) { + if (impl->state() == WeakImpl::Live) + return reinterpret_cast(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(slot) | UsingSingleSlotFlag; - } - HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast(structure)); - *slot = reinterpret_cast(structure); + if (WeakImpl* impl = this->weakImpl()) + WeakHeap::deallocate(impl); + WeakImpl* impl = globalData.heap.weakHeap()->allocate(reinterpret_cast(structure)); + m_data = reinterpret_cast(impl) | UsingSingleSlotFlag; } intptr_t m_data; diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h index f01a0c8..e964835 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -51,7 +51,7 @@ class WeakGCMap : private WeakHandleOwner { WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(WeakGCMap); - typedef HashMap MapType; + typedef HashMap MapType; typedef typename HandleTypes::ExternalType ExternalType; typedef typename MapType::iterator map_iterator; @@ -64,8 +64,7 @@ public: { } - std::pair get() const { return std::make_pair(m_iterator->first, HandleTypes::getFromSlot(m_iterator->second)); } - std::pair getSlot() const { return *m_iterator; } + std::pair get() const { return std::make_pair(m_iterator->first, HandleTypes::getFromSlot(const_cast(&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::getFromSlot(m_map.get(key)); - } - - HandleSlot getSlot(const KeyType& key) const - { - return m_map.get(key); + return HandleTypes::getFromSlot(const_cast(&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::emptyValue(); - ExternalType result = HandleTypes::getFromSlot(slot); - HandleHeap::heapFor(slot)->deallocate(slot); + ExternalType result = HandleTypes::getFromSlot(const_cast(&impl->jsValue())); + WeakHeap::deallocate(impl); return result; } @@ -181,9 +158,9 @@ public: private: virtual void finalize(Handle handle, void* context) { - HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes::getFromSlot(handle.slot()))); - ASSERT(slot); - HandleHeap::heapFor(slot)->deallocate(slot); + WeakImpl* impl = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes::getFromSlot(handle.slot()))); + ASSERT(impl); + WeakHeap::deallocate(impl); } MapType m_map; diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 4373ef0..30c12b9 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,32 @@ +2012-03-29 Geoffrey Garen + + First step toward incremental Weak finalization + https://bugs.webkit.org/show_bug.cgi?id=82670 + + Reviewed by Filip Pizlo. + + Updated WebCore for Weak API changes. + + * bindings/js/DOMWrapperWorld.cpp: + (WebCore::JSStringOwner::finalize): We're not allowed to get() a dead Weak + 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, so I had to push down these ASSERTs into ScriptWrappable. + + * bindings/js/JSNodeFilterCondition.cpp: + (WebCore::JSNodeFilterCondition::acceptNode): Updated for non-Handle-ness + of Weak. + + * bindings/js/ScriptWrappable.h: + (WebCore::ScriptWrappable::setWrapper): + (WebCore::ScriptWrappable::clearWrapper): Use was(), as above. + 2012-04-03 Luke Macpherson Don't parse "show" and "hide" as valid values for display property. diff --git a/Source/WebCore/bindings/js/DOMWrapperWorld.cpp b/Source/WebCore/bindings/js/DOMWrapperWorld.cpp index 812549b..d082242 100644 --- a/Source/WebCore/bindings/js/DOMWrapperWorld.cpp +++ b/Source/WebCore/bindings/js/DOMWrapperWorld.cpp @@ -34,7 +34,7 @@ void JSStringOwner::finalize(JSC::Handle handle, void* context) { JSString* jsString = static_cast(handle.get().asCell()); StringImpl* stringImpl = static_cast(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); } diff --git a/Source/WebCore/bindings/js/JSDOMBinding.h b/Source/WebCore/bindings/js/JSDOMBinding.h index 7eebc77..98746e9 100644 --- a/Source/WebCore/bindings/js/JSDOMBinding.h +++ b/Source/WebCore/bindings/js/JSDOMBinding.h @@ -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); } diff --git a/Source/WebCore/bindings/js/JSNodeCustom.h b/Source/WebCore/bindings/js/JSNodeCustom.h index 7688eea..518b21d 100644 --- a/Source/WebCore/bindings/js/JSNodeCustom.h +++ b/Source/WebCore/bindings/js/JSNodeCustom.h @@ -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; } diff --git a/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp b/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp index 91b9156..ce24752 100644 --- a/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp +++ b/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp @@ -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 diff --git a/Source/WebCore/bindings/js/ScriptWrappable.h b/Source/WebCore/bindings/js/ScriptWrappable.h index 92d05e8..73b2d6f 100644 --- a/Source/WebCore/bindings/js/ScriptWrappable.h +++ b/Source/WebCore/bindings/js/ScriptWrappable.h @@ -45,11 +45,13 @@ public: void setWrapper(JSC::JSGlobalData& globalData, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) { + ASSERT(!m_wrapper); m_wrapper = JSC::PassWeak(globalData, wrapper, wrapperOwner, context); } - void clearWrapper() + void clearWrapper(JSDOMWrapper* wrapper) { + ASSERT_UNUSED(wrapper, m_wrapper.was(wrapper)); m_wrapper.clear(); } diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog index 45831cb..6982213 100644 --- a/Source/WebKit2/ChangeLog +++ b/Source/WebKit2/ChangeLog @@ -1,3 +1,15 @@ +2012-03-29 Geoffrey Garen + + First step toward incremental Weak 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 Disable ENABLE_DATALIST for now diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp index 01e73f9..b4f0381 100644 --- a/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp +++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp @@ -292,7 +292,7 @@ void NPRuntimeObjectMap::finalize(JSC::Handle handle, void* contex { HashMap >::iterator found = m_jsNPObjects.find(static_cast(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()); diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp index 6983984..e62d539 100644 --- a/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp +++ b/Source/WebKit2/WebProcess/Plugins/Netscape/NetscapePlugin.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include diff --git a/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp index b215271..8339ad4 100644 --- a/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp +++ b/Source/WebKit2/WebProcess/Plugins/PluginProcessConnection.cpp @@ -28,6 +28,8 @@ #if ENABLE(PLUGIN_PROCESS) +#include +#include #include "NPRemoteObjectMap.h" #include "NPRuntimeObjectMap.h" #include "PluginProcessConnectionManager.h" -- 2.7.4