From d342e879385c8c8321064775f2d2c4b7eca437d1 Mon Sep 17 00:00:00 2001 From: "mjs@apple.com" Date: Wed, 28 Nov 2007 10:08:09 +0000 Subject: [PATCH] JavaScriptCore: Reviewed by Darin and Geoff. - Fixed "Stack overflow crash in JavaScript garbage collector mark pass" http://bugs.webkit.org/show_bug.cgi?id=12216 Implement mark stack. This version is not suitable for prime time because it makes a huge allocation on every collect, and potentially makes marking of detached subtrees slow. But it is an 0.4% SunSpider speedup even without much tweaking. The basic approach is to replace mark() methods with markChildren(MarkStack&) methods. Reachable references are pushed onto a mark stack (which encapsulates ignoring already-marked references). Objects are no longer responsible for actually setting their own mark bits, the collector does that. This means that for objects on the number heap we don't have to call markChildren() at all since we know there aren't any. The mark phase of collect pushes roots onto the mark stack and drains it as often as possible. To make this approach viable requires a constant-size mark stack and a slow fallback approach for when the stack size is exceeded, plus optimizations to make the required stack small in common cases. This should be doable. * JavaScriptCore.exp: Export new symbols. * JavaScriptCore.xcodeproj/project.pbxproj: Add new file. * kjs/collector.cpp: (KJS::Collector::heapAllocate): (KJS::drainMarkStack): Helper for all of the below. (KJS::Collector::markStackObjectsConservatively): Use mark stack. (KJS::Collector::markCurrentThreadConservatively): ditto (KJS::Collector::markOtherThreadConservatively): ditto (KJS::Collector::markProtectedObjects): ditto (KJS::Collector::markMainThreadOnlyObjects): ditto (KJS::Collector::collect): ditto * kjs/collector.h: (KJS::Collector::cellMayHaveRefs): Helper for MarkStack. * kjs/MarkStack.h: Added. The actual mark stack implementation. (KJS::MarkStack::push): (KJS::MarkStack::pushAtom): (KJS::MarkStack::pop): (KJS::MarkStack::isEmpty): (KJS::MarkStack::reserveCapacity): Changed mark() methods to markChildren() methods: * kjs/ExecState.cpp: (KJS::ExecState::markChildren): * kjs/ExecState.h: * kjs/JSWrapperObject.cpp: (KJS::JSWrapperObject::markChildren): * kjs/JSWrapperObject.h: * kjs/array_instance.cpp: (KJS::ArrayInstance::markChildren): * kjs/array_instance.h: * kjs/bool_object.cpp: (BooleanInstance::markChildren): * kjs/bool_object.h: * kjs/error_object.cpp: * kjs/error_object.h: * kjs/function.cpp: (KJS::FunctionImp::markChildren): (KJS::Arguments::Arguments): (KJS::Arguments::markChildren): (KJS::ActivationImp::markChildren): * kjs/function.h: * kjs/internal.cpp: (KJS::GetterSetterImp::markChildren): * kjs/interpreter.cpp: (KJS::Interpreter::markRoots): * kjs/interpreter.h: * kjs/list.cpp: (KJS::List::markProtectedListsSlowCase): * kjs/list.h: (KJS::List::markProtectedLists): * kjs/object.cpp: (KJS::JSObject::markChildren): * kjs/object.h: (KJS::ScopeChain::markChildren): * kjs/property_map.cpp: (KJS::PropertyMap::markChildren): * kjs/property_map.h: * kjs/scope_chain.h: * kjs/string_object.cpp: (KJS::StringInstance::markChildren): * kjs/string_object.h: JavaScriptGlue: Reviewed by Darin and Geoff. Fixups for JavaScriptCore mark stack. * JSObject.cpp: (JSUserObject::Mark): * JSObject.h: * JSValueWrapper.cpp: (JSValueWrapper::JSObjectMark): * JSValueWrapper.h: * UserObjectImp.cpp: * UserObjectImp.h: WebCore: Reviewed by Darin and Geoff. Implement mark stack. This version is not suitable for prime time because it makes a huge allocation on every collect, and potentially makes marking of detached subtrees slow. But it is a .2% - .4% speedup even without much tweaking. I replaced mark() methods with markChildren() as usual. One optimization that is lost is avoiding walking detached DOM subtrees more than once to mark them; since marking is not recursive there's no obvious way to bracket operation on the tree any more. * bindings/js/JSDocumentCustom.cpp: (WebCore::JSDocument::markChildren): * bindings/js/JSNodeCustom.cpp: (WebCore::JSNode::markChildren): * bindings/js/JSNodeFilterCondition.cpp: * bindings/js/JSNodeFilterCondition.h: * bindings/js/JSNodeFilterCustom.cpp: (WebCore::JSNodeFilter::markChildren): * bindings/js/JSNodeIteratorCustom.cpp: (WebCore::JSNodeIterator::markChildren): * bindings/js/JSTreeWalkerCustom.cpp: (WebCore::JSTreeWalker::markChildren): * bindings/js/JSXMLHttpRequest.cpp: (KJS::JSXMLHttpRequest::markChildren): * bindings/js/JSXMLHttpRequest.h: * bindings/js/kjs_binding.cpp: (KJS::ScriptInterpreter::markDOMNodesForDocument): * bindings/js/kjs_binding.h: * bindings/js/kjs_events.cpp: (WebCore::JSUnprotectedEventListener::markChildren): * bindings/js/kjs_events.h: * bindings/js/kjs_window.cpp: (KJS::Window::markChildren): * bindings/js/kjs_window.h: * bindings/scripts/CodeGeneratorJS.pm: * dom/Node.cpp: (WebCore::Node::Node): * dom/Node.h: * dom/NodeFilter.h: * dom/NodeFilterCondition.h: LayoutTests: Not reviewed. - Test cases for "Stack overflow crash in JavaScript garbage collector mark pass" http://bugs.webkit.org/show_bug.cgi?id=12216 I have fixed this with the mark stack work. * fast/js/gc-breadth-2-expected.txt: Added. * fast/js/gc-breadth-2.html: Added. * fast/js/gc-breadth-expected.txt: Added. * fast/js/gc-breadth.html: Added. * fast/js/gc-depth-expected.txt: Added. * fast/js/gc-depth.html: Added. * fast/js/resources/gc-breadth-2.js: Added. * fast/js/resources/gc-breadth.js: Added. * fast/js/resources/gc-depth.js: Added. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@28106 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- JavaScriptCore/ChangeLog | 93 +++++++++++ JavaScriptCore/JavaScriptCore.exp | 6 +- .../JavaScriptCore.xcodeproj/project.pbxproj | 4 + JavaScriptCore/kjs/ExecState.cpp | 4 +- JavaScriptCore/kjs/ExecState.h | 2 +- JavaScriptCore/kjs/JSWrapperObject.cpp | 7 +- JavaScriptCore/kjs/JSWrapperObject.h | 4 +- JavaScriptCore/kjs/array_instance.cpp | 15 +- JavaScriptCore/kjs/array_instance.h | 2 +- JavaScriptCore/kjs/bool_object.cpp | 6 + JavaScriptCore/kjs/bool_object.h | 1 + JavaScriptCore/kjs/collector.cpp | 64 +++++--- JavaScriptCore/kjs/collector.h | 25 ++- JavaScriptCore/kjs/error_object.cpp | 6 - JavaScriptCore/kjs/error_object.h | 2 - JavaScriptCore/kjs/function.cpp | 39 ++--- JavaScriptCore/kjs/function.h | 6 +- JavaScriptCore/kjs/internal.cpp | 12 +- JavaScriptCore/kjs/interpreter.cpp | 144 +++++++++--------- JavaScriptCore/kjs/interpreter.h | 2 +- JavaScriptCore/kjs/list.cpp | 9 +- JavaScriptCore/kjs/list.h | 6 +- JavaScriptCore/kjs/object.cpp | 11 +- JavaScriptCore/kjs/object.h | 14 +- JavaScriptCore/kjs/property_map.cpp | 16 +- JavaScriptCore/kjs/property_map.h | 3 +- JavaScriptCore/kjs/scope_chain.h | 2 +- JavaScriptCore/kjs/string_object.cpp | 6 + JavaScriptCore/kjs/string_object.h | 1 + JavaScriptCore/kjs/value.h | 15 +- JavaScriptGlue/ChangeLog | 15 ++ JavaScriptGlue/JSObject.cpp | 4 +- JavaScriptGlue/JSObject.h | 4 +- JavaScriptGlue/JSValueWrapper.cpp | 4 +- JavaScriptGlue/JSValueWrapper.h | 2 +- JavaScriptGlue/UserObjectImp.cpp | 6 +- JavaScriptGlue/UserObjectImp.h | 2 +- LayoutTests/ChangeLog | 19 +++ WebCore/ChangeLog | 45 ++++++ WebCore/bindings/js/JSDocumentCustom.cpp | 6 +- WebCore/bindings/js/JSNodeCustom.cpp | 33 +--- WebCore/bindings/js/JSNodeFilterCondition.cpp | 4 +- WebCore/bindings/js/JSNodeFilterCondition.h | 2 +- WebCore/bindings/js/JSNodeFilterCustom.cpp | 6 +- WebCore/bindings/js/JSNodeIteratorCustom.cpp | 6 +- WebCore/bindings/js/JSTreeWalkerCustom.cpp | 6 +- WebCore/bindings/js/JSXMLHttpRequest.cpp | 10 +- WebCore/bindings/js/JSXMLHttpRequest.h | 2 +- WebCore/bindings/js/kjs_binding.cpp | 8 +- WebCore/bindings/js/kjs_binding.h | 2 +- WebCore/bindings/js/kjs_events.cpp | 6 +- WebCore/bindings/js/kjs_events.h | 2 +- WebCore/bindings/js/kjs_window.cpp | 8 +- WebCore/bindings/js/kjs_window.h | 2 +- WebCore/bindings/scripts/CodeGeneratorJS.pm | 2 +- WebCore/dom/Node.cpp | 3 +- WebCore/dom/Node.h | 4 +- WebCore/dom/NodeFilter.h | 6 +- WebCore/dom/NodeFilterCondition.h | 6 +- 59 files changed, 460 insertions(+), 292 deletions(-) diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 203f95fa4ab..dc7d94db82e 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,96 @@ +2007-11-28 Maciej Stachowiak + + Reviewed by Darin and Geoff. + + - Fixed "Stack overflow crash in JavaScript garbage collector mark pass" + http://bugs.webkit.org/show_bug.cgi?id=12216 + + Implement mark stack. This version is not suitable for prime time because it makes a + huge allocation on every collect, and potentially makes marking of detached subtrees + slow. But it is an 0.4% SunSpider speedup even without much tweaking. + + The basic approach is to replace mark() methods with + markChildren(MarkStack&) methods. Reachable references are pushed + onto a mark stack (which encapsulates ignoring already-marked + references). + + Objects are no longer responsible for actually setting their own + mark bits, the collector does that. This means that for objects on + the number heap we don't have to call markChildren() at all since + we know there aren't any. + + The mark phase of collect pushes roots onto the mark stack + and drains it as often as possible. + + To make this approach viable requires a constant-size mark stack + and a slow fallback approach for when the stack size is exceeded, + plus optimizations to make the required stack small in common + cases. This should be doable. + + * JavaScriptCore.exp: Export new symbols. + * JavaScriptCore.xcodeproj/project.pbxproj: Add new file. + * kjs/collector.cpp: + (KJS::Collector::heapAllocate): + (KJS::drainMarkStack): Helper for all of the below. + (KJS::Collector::markStackObjectsConservatively): Use mark stack. + (KJS::Collector::markCurrentThreadConservatively): ditto + (KJS::Collector::markOtherThreadConservatively): ditto + (KJS::Collector::markProtectedObjects): ditto + (KJS::Collector::markMainThreadOnlyObjects): ditto + (KJS::Collector::collect): ditto + * kjs/collector.h: + (KJS::Collector::cellMayHaveRefs): Helper for MarkStack. + + * kjs/MarkStack.h: Added. The actual mark stack implementation. + (KJS::MarkStack::push): + (KJS::MarkStack::pushAtom): + (KJS::MarkStack::pop): + (KJS::MarkStack::isEmpty): + (KJS::MarkStack::reserveCapacity): + + Changed mark() methods to markChildren() methods: + + * kjs/ExecState.cpp: + (KJS::ExecState::markChildren): + * kjs/ExecState.h: + * kjs/JSWrapperObject.cpp: + (KJS::JSWrapperObject::markChildren): + * kjs/JSWrapperObject.h: + * kjs/array_instance.cpp: + (KJS::ArrayInstance::markChildren): + * kjs/array_instance.h: + * kjs/bool_object.cpp: + (BooleanInstance::markChildren): + * kjs/bool_object.h: + * kjs/error_object.cpp: + * kjs/error_object.h: + * kjs/function.cpp: + (KJS::FunctionImp::markChildren): + (KJS::Arguments::Arguments): + (KJS::Arguments::markChildren): + (KJS::ActivationImp::markChildren): + * kjs/function.h: + * kjs/internal.cpp: + (KJS::GetterSetterImp::markChildren): + * kjs/interpreter.cpp: + (KJS::Interpreter::markRoots): + * kjs/interpreter.h: + * kjs/list.cpp: + (KJS::List::markProtectedListsSlowCase): + * kjs/list.h: + (KJS::List::markProtectedLists): + * kjs/object.cpp: + (KJS::JSObject::markChildren): + * kjs/object.h: + (KJS::ScopeChain::markChildren): + * kjs/property_map.cpp: + (KJS::PropertyMap::markChildren): + * kjs/property_map.h: + * kjs/scope_chain.h: + * kjs/string_object.cpp: + (KJS::StringInstance::markChildren): + * kjs/string_object.h: + 2007-11-27 Alp Toker Reviewed by Mark Rowe. diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index 35f01b7b1e3..b33faef0615 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -122,10 +122,10 @@ __ZN3KJS11Interpreter17startTimeoutCheckEv __ZN3KJS11Interpreter21shouldPrintExceptionsEv __ZN3KJS11Interpreter24setShouldPrintExceptionsEb __ZN3KJS11Interpreter27resetGlobalObjectPropertiesEv -__ZN3KJS11Interpreter4markEv __ZN3KJS11Interpreter6s_hookE __ZN3KJS11Interpreter8evaluateERKNS_7UStringEiPKNS_5UCharEiPNS_7JSValueE __ZN3KJS11Interpreter8evaluateERKNS_7UStringEiS3_PNS_7JSValueE +__ZN3KJS11Interpreter9markRootsERNS_9MarkStackE __ZN3KJS11InterpreterC1Ev __ZN3KJS11InterpreterC2Ev __ZN3KJS11InterpreterD1Ev @@ -144,6 +144,7 @@ __ZN3KJS13ArrayInstance4infoE __ZN3KJS13SavedBuiltinsC1Ev __ZN3KJS13SavedBuiltinsD1Ev __ZN3KJS13jsOwnedStringERKNS_7UStringE +__ZN3KJS14StringInstance12markChildrenERNS_9MarkStackE __ZN3KJS14StringInstance14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE __ZN3KJS14StringInstance16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE __ZN3KJS14StringInstance18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE @@ -152,7 +153,6 @@ __ZN3KJS14StringInstance3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi __ZN3KJS14StringInstance4infoE __ZN3KJS14StringInstanceC1EPNS_8JSObjectERKNS_7UStringE __ZN3KJS14StringInstanceC2EPNS_8JSObjectERKNS_7UStringE -__ZN3KJS15JSWrapperObject4markEv __ZN3KJS15SavedPropertiesC1Ev __ZN3KJS15SavedPropertiesD1Ev __ZN3KJS16RuntimeObjectImp4infoE @@ -201,6 +201,7 @@ __ZN3KJS8Debugger9exceptionEPNS_9ExecStateEiiPNS_7JSValueE __ZN3KJS8DebuggerC2Ev __ZN3KJS8DebuggerD2Ev __ZN3KJS8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE +__ZN3KJS8JSObject12markChildrenERNS_9MarkStackE __ZN3KJS8JSObject12removeDirectERKNS_10IdentifierE __ZN3KJS8JSObject14callAsFunctionEPNS_9ExecStateEPS0_RKNS_4ListE __ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE @@ -212,7 +213,6 @@ __ZN3KJS8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPPNS_7JSValueE __ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi __ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueEi __ZN3KJS8JSObject4callEPNS_9ExecStateEPS0_RKNS_4ListE -__ZN3KJS8JSObject4markEv __ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListE __ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListERKNS_10IdentifierERKNS_7UStringEi __ZN3KJS8JSObject9putDirectERKNS_10IdentifierEPNS_7JSValueEi diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 99a0e2f68b7..d81d49566b6 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -99,6 +99,7 @@ 6592C318098B7DE10003D4F6 /* Vector.h in Headers */ = {isa = PBXBuildFile; fileRef = 6592C316098B7DE10003D4F6 /* Vector.h */; settings = {ATTRIBUTES = (Private, ); }; }; 6592C319098B7DE10003D4F6 /* VectorTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 6592C317098B7DE10003D4F6 /* VectorTraits.h */; settings = {ATTRIBUTES = (Private, ); }; }; 65A7A5E00CD1D50E00061F8E /* LabelStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B813A80CD1D01900DF59D6 /* LabelStack.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 65A8B8DB0CF408F400DC7C27 /* MarkStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 65A8B8D80CF408E900DC7C27 /* MarkStack.h */; settings = {ATTRIBUTES = (Private, ); }; }; 65B1749A09D0FEB700820339 /* array_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B1749909D0FEB700820339 /* array_object.lut.h */; }; 65B174F509D100FA00820339 /* math_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B174F109D100FA00820339 /* math_object.lut.h */; }; 65B174F609D100FA00820339 /* number_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B174F209D100FA00820339 /* number_object.lut.h */; }; @@ -510,6 +511,7 @@ 659126BC0BDD1728001921FB /* AllInOneFile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AllInOneFile.cpp; sourceTree = ""; }; 6592C316098B7DE10003D4F6 /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = ""; }; 6592C317098B7DE10003D4F6 /* VectorTraits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VectorTraits.h; sourceTree = ""; }; + 65A8B8D80CF408E900DC7C27 /* MarkStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStack.h; sourceTree = ""; }; 65B1749909D0FEB700820339 /* array_object.lut.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = array_object.lut.h; path = ../../../../../symroots/Debug/DerivedSources/JavaScriptCore/array_object.lut.h; sourceTree = ""; }; 65B174BE09D1000200820339 /* chartables.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 30; path = chartables.c; sourceTree = ""; }; 65B174F109D100FA00820339 /* math_object.lut.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = math_object.lut.h; path = ../../../../../symroots/Debug/DerivedSources/JavaScriptCore/math_object.lut.h; sourceTree = ""; }; @@ -1008,6 +1010,7 @@ F692A8680255597D01FF60F7 /* lookup.cpp */, F692A8690255597D01FF60F7 /* lookup.h */, F692A86A0255597D01FF60F7 /* math_object.cpp */, + 65A8B8D80CF408E900DC7C27 /* MarkStack.h */, F692A86B0255597D01FF60F7 /* math_object.h */, F692A86D0255597D01FF60F7 /* nodes.cpp */, F692A86E0255597D01FF60F7 /* nodes.h */, @@ -1170,6 +1173,7 @@ 148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */, 65F340940CD6C1C000C0CA8B /* LocalStorage.h in Headers */, 5DBD18B00C5401A700C15EAE /* MallocZoneSupport.h in Headers */, + 65A8B8DB0CF408F400DC7C27 /* MarkStack.h in Headers */, BCF655590A2049710038A194 /* MathExtras.h in Headers */, 932F5B840822A1C700736975 /* NP_jsobject.h in Headers */, 9303F56A0991190000AD71B8 /* Noncopyable.h in Headers */, diff --git a/JavaScriptCore/kjs/ExecState.cpp b/JavaScriptCore/kjs/ExecState.cpp index f828a691404..5a22e6959fd 100644 --- a/JavaScriptCore/kjs/ExecState.cpp +++ b/JavaScriptCore/kjs/ExecState.cpp @@ -88,10 +88,10 @@ ExecState::~ExecState() m_interpreter->setCurrentExec(m_savedExecState); } -void ExecState::mark() +void ExecState::markChildren(MarkStack& stack) { for (ExecState* exec = this; exec; exec = exec->m_callingExecState) - exec->m_scopeChain.mark(); + exec->m_scopeChain.markChildren(stack); } void ExecState::setGlobalObject(JSGlobalObject* globalObject) diff --git a/JavaScriptCore/kjs/ExecState.h b/JavaScriptCore/kjs/ExecState.h index 5012350be7e..65f233f80ce 100644 --- a/JavaScriptCore/kjs/ExecState.h +++ b/JavaScriptCore/kjs/ExecState.h @@ -100,7 +100,7 @@ namespace KJS { void setGlobalObject(JSGlobalObject*); - void mark(); + void markChildren(MarkStack&); // This is a workaround to avoid accessing the global variables for these identifiers in // important property lookup functions, to avoid taking PIC branches in Mach-O binaries diff --git a/JavaScriptCore/kjs/JSWrapperObject.cpp b/JavaScriptCore/kjs/JSWrapperObject.cpp index dd161f7afda..36e7584a081 100644 --- a/JavaScriptCore/kjs/JSWrapperObject.cpp +++ b/JavaScriptCore/kjs/JSWrapperObject.cpp @@ -24,11 +24,10 @@ namespace KJS { -void JSWrapperObject::mark() +void JSWrapperObject::markChildren(MarkStack& stack) { - JSObject::mark(); - if (m_internalValue && !m_internalValue->marked()) - m_internalValue->mark(); + JSObject::markChildren(stack); + stack.pushAtom(m_internalValue); } } // namespace KJS diff --git a/JavaScriptCore/kjs/JSWrapperObject.h b/JavaScriptCore/kjs/JSWrapperObject.h index 0a06c9fec3c..d51f0bd6cc0 100644 --- a/JavaScriptCore/kjs/JSWrapperObject.h +++ b/JavaScriptCore/kjs/JSWrapperObject.h @@ -56,7 +56,7 @@ namespace KJS { */ void setInternalValue(JSValue* v); - virtual void mark(); + virtual void markChildren(MarkStack& stack); private: JSValue* m_internalValue; @@ -64,7 +64,7 @@ namespace KJS { inline JSWrapperObject::JSWrapperObject(JSValue* proto) : JSObject(proto) - , m_internalValue(0) + , m_internalValue(jsNull()) { } diff --git a/JavaScriptCore/kjs/array_instance.cpp b/JavaScriptCore/kjs/array_instance.cpp index 28251323292..e940786b6fe 100644 --- a/JavaScriptCore/kjs/array_instance.cpp +++ b/JavaScriptCore/kjs/array_instance.cpp @@ -402,26 +402,23 @@ void ArrayInstance::setLength(unsigned newLength) m_length = newLength; } -void ArrayInstance::mark() +void ArrayInstance::markChildren(MarkStack& stack) { - JSObject::mark(); + JSObject::markChildren(stack); ArrayStorage* storage = m_storage; unsigned usedVectorLength = min(m_length, m_vectorLength); for (unsigned i = 0; i < usedVectorLength; ++i) { JSValue* value = storage->m_vector[i]; - if (value && !value->marked()) - value->mark(); + if (value) + stack.push(value); } if (SparseArrayValueMap* map = storage->m_sparseValueMap) { SparseArrayValueMap::iterator end = map->end(); - for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { - JSValue* value = it->second; - if (!value->marked()) - value->mark(); - } + for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) + stack.push(it->second); } } diff --git a/JavaScriptCore/kjs/array_instance.h b/JavaScriptCore/kjs/array_instance.h index 913d0cdcf14..bb0a38e356b 100644 --- a/JavaScriptCore/kjs/array_instance.h +++ b/JavaScriptCore/kjs/array_instance.h @@ -42,7 +42,7 @@ namespace KJS { virtual bool deleteProperty(ExecState *, unsigned propertyName); virtual void getPropertyNames(ExecState*, PropertyNameArray&); - virtual void mark(); + virtual void markChildren(MarkStack&); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/JavaScriptCore/kjs/bool_object.cpp b/JavaScriptCore/kjs/bool_object.cpp index 916fe53ce55..a93c53d1351 100644 --- a/JavaScriptCore/kjs/bool_object.cpp +++ b/JavaScriptCore/kjs/bool_object.cpp @@ -38,6 +38,12 @@ BooleanInstance::BooleanInstance(JSObject *proto) { } +void BooleanInstance::markChildren(MarkStack& stack) +{ + JSObject::markChildren(stack); + ASSERT(JSImmediate::isImmediate(internalValue())); +} + // ------------------------------ BooleanPrototype -------------------------- // ECMA 15.6.4 diff --git a/JavaScriptCore/kjs/bool_object.h b/JavaScriptCore/kjs/bool_object.h index 3ab04a76f7e..2b8c0002fed 100644 --- a/JavaScriptCore/kjs/bool_object.h +++ b/JavaScriptCore/kjs/bool_object.h @@ -32,6 +32,7 @@ namespace KJS { BooleanInstance(JSObject *proto); virtual const ClassInfo *classInfo() const { return &info; } + virtual void markChildren(MarkStack& stack); static const ClassInfo info; }; diff --git a/JavaScriptCore/kjs/collector.cpp b/JavaScriptCore/kjs/collector.cpp index 7adfb8256a3..34934e0f083 100644 --- a/JavaScriptCore/kjs/collector.cpp +++ b/JavaScriptCore/kjs/collector.cpp @@ -26,6 +26,7 @@ #include "ExecState.h" #include "internal.h" #include "list.h" +#include "MarkStack.h" #include "value.h" #include #include @@ -277,6 +278,8 @@ collect: targetBlock = (Block*)allocateBlock(); targetBlock->freeList = targetBlock->cells; + if (heapType == PrimaryHeap) + targetBlock->mayHaveRefs = 1; targetBlockUsedCells = 0; heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock; heap.usedBlocks = usedBlocks + 1; @@ -479,7 +482,14 @@ void Collector::registerThread() // cell size needs to be a power of two for this to be valid #define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0) -void Collector::markStackObjectsConservatively(void *start, void *end) +static inline void drainMarkStack(MarkStack& stack) +{ + while (!stack.isEmpty()) + stack.pop()->markChildren(stack); +} + + +void Collector::markStackObjectsConservatively(MarkStack& stack, void *start, void *end) { if (start > end) { void* tmp = start; @@ -521,8 +531,8 @@ void Collector::markStackObjectsConservatively(void *start, void *end) if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { if (((CollectorCell*)xAsBits)->u.freeCell.zeroIfFree != 0) { JSCell* imp = reinterpret_cast(xAsBits); - if (!imp->marked()) - imp->mark(); + stack.push(imp); + drainMarkStack(stack); } break; } @@ -533,7 +543,7 @@ void Collector::markStackObjectsConservatively(void *start, void *end) } } -void Collector::markCurrentThreadConservatively() +void Collector::markCurrentThreadConservatively(MarkStack& stack) { // setjmp forces volatile registers onto the stack jmp_buf registers; @@ -550,7 +560,7 @@ void Collector::markCurrentThreadConservatively() void* stackPointer = &dummy; void* stackBase = currentThreadStackBase(); - markStackObjectsConservatively(stackPointer, stackBase); + markStackObjectsConservatively(stack, stackPointer, stackBase); } #if USE(MULTIPLE_THREADS) @@ -693,7 +703,7 @@ static inline void* otherThreadStackBase(const PlatformThreadRegisters& regs, Co #endif } -void Collector::markOtherThreadConservatively(Thread* thread) +void Collector::markOtherThreadConservatively(MarkStack& stack, Thread* thread) { suspendThread(thread->platformThread); @@ -701,25 +711,25 @@ void Collector::markOtherThreadConservatively(Thread* thread) size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); // mark the thread's registers - markStackObjectsConservatively((void*)®s, (void*)((char*)®s + regSize)); + markStackObjectsConservatively(stack, (void*)®s, (void*)((char*)®s + regSize)); void* stackPointer = otherThreadStackPointer(regs); void* stackBase = otherThreadStackBase(regs, thread); - markStackObjectsConservatively(stackPointer, stackBase); + markStackObjectsConservatively(stack, stackPointer, stackBase); resumeThread(thread->platformThread); } #endif -void Collector::markStackObjectsConservatively() +void Collector::markStackObjectsConservatively(MarkStack& stack) { - markCurrentThreadConservatively(); + markCurrentThreadConservatively(stack); #if USE(MULTIPLE_THREADS) for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) { if (!pthread_equal(thread->posixThread, pthread_self())) { - markOtherThreadConservatively(thread); + markOtherThreadConservatively(stack, thread); } } #endif @@ -771,18 +781,17 @@ void Collector::collectOnMainThreadOnly(JSValue* value) ++mainThreadOnlyObjectCount; } -void Collector::markProtectedObjects() +void Collector::markProtectedObjects(MarkStack& stack) { ProtectCountSet& protectedValues = KJS::protectedValues(); ProtectCountSet::iterator end = protectedValues.end(); for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) { - JSCell *val = it->first; - if (!val->marked()) - val->mark(); + stack.push(it->first); + drainMarkStack(stack); } } -void Collector::markMainThreadOnlyObjects() +void Collector::markMainThreadOnlyObjects(MarkStack& stack) { #if USE(MULTIPLE_THREADS) ASSERT(!onMainThread()); @@ -814,7 +823,8 @@ void Collector::markMainThreadOnlyObjects() if (curBlock->collectOnMainThreadOnly.get(i)) { if (!curBlock->marked.get(i)) { JSCell* imp = reinterpret_cast(cell); - imp->mark(); + stack.push(imp); + drainMarkStack(stack); } if (++count == mainThreadOnlyObjectCount) return; @@ -950,9 +960,14 @@ bool Collector::collect() // MARK: first mark all referenced objects recursively starting out from the set of root objects + size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects; + + MarkStack stack; + stack.reserveCapacity(primaryHeap.numLiveObjects); + #ifndef NDEBUG // Forbid malloc during the mark phase. Marking a thread suspends it, so - // a malloc inside mark() would risk a deadlock with a thread that had been + // a malloc inside markChildren() would risk a deadlock with a thread that had been // suspended while holding the malloc lock. fastMallocForbid(); #endif @@ -960,24 +975,25 @@ bool Collector::collect() if (Interpreter::s_hook) { Interpreter* scr = Interpreter::s_hook; do { - scr->mark(); + scr->markRoots(stack); + drainMarkStack(stack); scr = scr->next; } while (scr != Interpreter::s_hook); } - markStackObjectsConservatively(); - markProtectedObjects(); - List::markProtectedLists(); + markStackObjectsConservatively(stack); + markProtectedObjects(stack); + List::markProtectedLists(stack); + drainMarkStack(stack); #if USE(MULTIPLE_THREADS) if (!currentThreadIsMainThread) - markMainThreadOnlyObjects(); + markMainThreadOnlyObjects(stack); #endif #ifndef NDEBUG fastMallocAllow(); #endif - size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects; size_t numLiveObjects = sweep(currentThreadIsMainThread); numLiveObjects += sweep(currentThreadIsMainThread); diff --git a/JavaScriptCore/kjs/collector.h b/JavaScriptCore/kjs/collector.h index c8372f7d01c..60990a6c55d 100644 --- a/JavaScriptCore/kjs/collector.h +++ b/JavaScriptCore/kjs/collector.h @@ -31,9 +31,10 @@ namespace KJS { + class CollectorBlock; class JSCell; class JSValue; - class CollectorBlock; + class MarkStack; class Collector { public: @@ -65,6 +66,7 @@ namespace KJS { static bool isCellMarked(const JSCell*); static void markCell(JSCell*); + static bool cellMayHaveRefs(const JSCell*); enum HeapType { PrimaryHeap, NumberHeap }; @@ -78,12 +80,12 @@ namespace KJS { Collector(); static void recordExtraCost(size_t); - static void markProtectedObjects(); - static void markMainThreadOnlyObjects(); - static void markCurrentThreadConservatively(); - static void markOtherThreadConservatively(Thread*); - static void markStackObjectsConservatively(); - static void markStackObjectsConservatively(void* start, void* end); + static void markProtectedObjects(MarkStack&); + static void markMainThreadOnlyObjects(MarkStack&); + static void markCurrentThreadConservatively(MarkStack&); + static void markOtherThreadConservatively(MarkStack&, Thread*); + static void markStackObjectsConservatively(MarkStack&); + static void markStackObjectsConservatively(MarkStack&, void* start, void* end); static size_t mainThreadOnlyObjectCount; static bool memoryFull; @@ -107,7 +109,7 @@ namespace KJS { const size_t SMALL_CELL_SIZE = CELL_SIZE / 2; const size_t CELL_MASK = CELL_SIZE - 1; const size_t CELL_ALIGN_MASK = ~CELL_MASK; - const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2); + const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2); const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK; const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8; const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t); @@ -145,6 +147,7 @@ namespace KJS { CollectorCell cells[CELLS_PER_BLOCK]; uint32_t usedCells; CollectorCell* freeList; + uint32_t mayHaveRefs; CollectorBitmap marked; CollectorBitmap collectOnMainThreadOnly; }; @@ -154,6 +157,7 @@ namespace KJS { SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK]; uint32_t usedCells; SmallCollectorCell* freeList; + uint32_t mayHaveRefs; CollectorBitmap marked; CollectorBitmap collectOnMainThreadOnly; }; @@ -183,6 +187,11 @@ namespace KJS { cellBlock(cell)->marked.set(cellOffset(cell)); } + inline bool Collector::cellMayHaveRefs(const JSCell* cell) + { + return cellBlock(cell)->mayHaveRefs; + } + inline void Collector::reportExtraMemoryCost(size_t cost) { if (cost > minExtraCostSize) diff --git a/JavaScriptCore/kjs/error_object.cpp b/JavaScriptCore/kjs/error_object.cpp index 0697f107bd2..69a6151790e 100644 --- a/JavaScriptCore/kjs/error_object.cpp +++ b/JavaScriptCore/kjs/error_object.cpp @@ -156,9 +156,3 @@ JSValue* NativeErrorImp::callAsFunction(ExecState* exec, JSObject*, const List& return construct(exec, args); } -void NativeErrorImp::mark() -{ - JSObject::mark(); - if (proto && !proto->marked()) - proto->mark(); -} diff --git a/JavaScriptCore/kjs/error_object.h b/JavaScriptCore/kjs/error_object.h index 3e1ac8ae085..65154a76a5c 100644 --- a/JavaScriptCore/kjs/error_object.h +++ b/JavaScriptCore/kjs/error_object.h @@ -75,8 +75,6 @@ namespace KJS { virtual JSObject *construct(ExecState *exec, const List &args); virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args); - virtual void mark(); - virtual const ClassInfo *classInfo() const { return &info; } static const ClassInfo info; private: diff --git a/JavaScriptCore/kjs/function.cpp b/JavaScriptCore/kjs/function.cpp index 1dc40a4028f..49ebd89242d 100644 --- a/JavaScriptCore/kjs/function.cpp +++ b/JavaScriptCore/kjs/function.cpp @@ -61,10 +61,10 @@ FunctionImp::FunctionImp(ExecState* exec, const Identifier& name, FunctionBodyNo { } -void FunctionImp::mark() +void FunctionImp::markChildren(MarkStack& stack) { - InternalFunctionImp::mark(); - _scope.mark(); + InternalFunctionImp::markChildren(stack); + _scope.markChildren(stack); } JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) @@ -331,9 +331,9 @@ const ClassInfo Arguments::info = { "Arguments", 0, 0 }; // ECMA 10.1.8 Arguments::Arguments(ExecState* exec, FunctionImp* func, const List& args, ActivationImp* act) -: JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), -_activationObject(act), -indexToNameMap(func, args) + : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) + , _activationObject(act) + , indexToNameMap(func, args) { putDirect(exec->propertyNames().callee, func, DontEnum); putDirect(exec->propertyNames().length, args.size(), DontEnum); @@ -347,11 +347,10 @@ indexToNameMap(func, args) } } -void Arguments::mark() +void Arguments::markChildren(MarkStack& stack) { - JSObject::mark(); - if (_activationObject && !_activationObject->marked()) - _activationObject->mark(); + JSObject::markChildren(stack); + stack.push(_activationObject); } JSValue* Arguments::mappedIndexGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot) @@ -484,23 +483,17 @@ void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* val _prop.put(propertyName, value, attr, (attr == None || attr == DontDelete)); } -void ActivationImp::mark() +void ActivationImp::markChildren(MarkStack& stack) { - JSObject::mark(); + JSObject::markChildren(stack); size_t size = d->localStorage.size(); - for (size_t i = 0; i < size; ++i) { - JSValue* value = d->localStorage[i].value; - if (!value->marked()) - value->mark(); - } + for (size_t i = 0; i < size; ++i) + stack.push(d->localStorage[i].value); - ASSERT(d->function); - if (!d->function->marked()) - d->function->mark(); - - if (d->argumentsObject && !d->argumentsObject->marked()) - d->argumentsObject->mark(); + stack.push(d->function); + if (d->argumentsObject) + stack.push(d->argumentsObject); } void ActivationImp::createArgumentsObject(ExecState* exec) diff --git a/JavaScriptCore/kjs/function.h b/JavaScriptCore/kjs/function.h index 5657b1e71bf..392127e18a3 100644 --- a/JavaScriptCore/kjs/function.h +++ b/JavaScriptCore/kjs/function.h @@ -95,7 +95,7 @@ namespace KJS { void setScope(const ScopeChain& s) { _scope = s; } const ScopeChain& scope() const { return _scope; } - virtual void mark(); + virtual void markChildren(MarkStack&); private: ScopeChain _scope; @@ -124,7 +124,7 @@ namespace KJS { class Arguments : public JSObject { public: Arguments(ExecState*, FunctionImp* func, const List& args, ActivationImp* act); - virtual void mark(); + virtual void markChildren(MarkStack&); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual void put(ExecState*, const Identifier& propertyName, JSValue* value, int attr = None); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); @@ -164,7 +164,7 @@ namespace KJS { virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; - virtual void mark(); + virtual void markChildren(MarkStack&); bool isActivation() { return true; } diff --git a/JavaScriptCore/kjs/internal.cpp b/JavaScriptCore/kjs/internal.cpp index 125244e2e66..faf9f98a7fa 100644 --- a/JavaScriptCore/kjs/internal.cpp +++ b/JavaScriptCore/kjs/internal.cpp @@ -144,14 +144,12 @@ bool NumberImp::getTruncatedUInt32(uint32_t& uint32) const } // --------------------------- GetterSetterImp --------------------------------- -void GetterSetterImp::mark() +void GetterSetterImp::markChildren(MarkStack& stack) { - JSCell::mark(); - - if (getter && !getter->marked()) - getter->mark(); - if (setter && !setter->marked()) - setter->mark(); + if (getter) + stack.push(getter); + if (setter) + stack.push(setter); } JSValue* GetterSetterImp::toPrimitive(ExecState*, JSType) const diff --git a/JavaScriptCore/kjs/interpreter.cpp b/JavaScriptCore/kjs/interpreter.cpp index 2d381b20067..eb2bbc81a16 100644 --- a/JavaScriptCore/kjs/interpreter.cpp +++ b/JavaScriptCore/kjs/interpreter.cpp @@ -544,80 +544,80 @@ JSObject *Interpreter::builtinURIErrorPrototype() const return m_UriErrorPrototype; } -void Interpreter::mark() +void Interpreter::markRoots(MarkStack& stack) { if (m_currentExec) - m_currentExec->mark(); - - if (m_globalExec.exception() && !m_globalExec.exception()->marked()) - m_globalExec.exception()->mark(); - - if (m_globalObject && !m_globalObject->marked()) - m_globalObject->mark(); - - if (m_Object && !m_Object->marked()) - m_Object->mark(); - if (m_Function && !m_Function->marked()) - m_Function->mark(); - if (m_Array && !m_Array->marked()) - m_Array->mark(); - if (m_Boolean && !m_Boolean->marked()) - m_Boolean->mark(); - if (m_String && !m_String->marked()) - m_String->mark(); - if (m_Number && !m_Number->marked()) - m_Number->mark(); - if (m_Date && !m_Date->marked()) - m_Date->mark(); - if (m_RegExp && !m_RegExp->marked()) - m_RegExp->mark(); - if (m_Error && !m_Error->marked()) - m_Error->mark(); - - if (m_ObjectPrototype && !m_ObjectPrototype->marked()) - m_ObjectPrototype->mark(); - if (m_FunctionPrototype && !m_FunctionPrototype->marked()) - m_FunctionPrototype->mark(); - if (m_ArrayPrototype && !m_ArrayPrototype->marked()) - m_ArrayPrototype->mark(); - if (m_BooleanPrototype && !m_BooleanPrototype->marked()) - m_BooleanPrototype->mark(); - if (m_StringPrototype && !m_StringPrototype->marked()) - m_StringPrototype->mark(); - if (m_NumberPrototype && !m_NumberPrototype->marked()) - m_NumberPrototype->mark(); - if (m_DatePrototype && !m_DatePrototype->marked()) - m_DatePrototype->mark(); - if (m_RegExpPrototype && !m_RegExpPrototype->marked()) - m_RegExpPrototype->mark(); - if (m_ErrorPrototype && !m_ErrorPrototype->marked()) - m_ErrorPrototype->mark(); - - if (m_EvalError && !m_EvalError->marked()) - m_EvalError->mark(); - if (m_RangeError && !m_RangeError->marked()) - m_RangeError->mark(); - if (m_ReferenceError && !m_ReferenceError->marked()) - m_ReferenceError->mark(); - if (m_SyntaxError && !m_SyntaxError->marked()) - m_SyntaxError->mark(); - if (m_TypeError && !m_TypeError->marked()) - m_TypeError->mark(); - if (m_UriError && !m_UriError->marked()) - m_UriError->mark(); - - if (m_EvalErrorPrototype && !m_EvalErrorPrototype->marked()) - m_EvalErrorPrototype->mark(); - if (m_RangeErrorPrototype && !m_RangeErrorPrototype->marked()) - m_RangeErrorPrototype->mark(); - if (m_ReferenceErrorPrototype && !m_ReferenceErrorPrototype->marked()) - m_ReferenceErrorPrototype->mark(); - if (m_SyntaxErrorPrototype && !m_SyntaxErrorPrototype->marked()) - m_SyntaxErrorPrototype->mark(); - if (m_TypeErrorPrototype && !m_TypeErrorPrototype->marked()) - m_TypeErrorPrototype->mark(); - if (m_UriErrorPrototype && !m_UriErrorPrototype->marked()) - m_UriErrorPrototype->mark(); + m_currentExec->markChildren(stack); + + if (m_globalExec.exception()) + stack.push(m_globalExec.exception()); + + if (m_globalObject) + stack.push(m_globalObject); + + if (m_Object) + stack.push(m_Object); + if (m_Function) + stack.push(m_Function); + if (m_Array) + stack.push(m_Array); + if (m_Boolean) + stack.push(m_Boolean); + if (m_String) + stack.push(m_String); + if (m_Number) + stack.push(m_Number); + if (m_Date) + stack.push(m_Date); + if (m_RegExp) + stack.push(m_RegExp); + if (m_Error) + stack.push(m_Error); + + if (m_ObjectPrototype) + stack.push(m_ObjectPrototype); + if (m_FunctionPrototype) + stack.push(m_FunctionPrototype); + if (m_ArrayPrototype) + stack.push(m_ArrayPrototype); + if (m_BooleanPrototype) + stack.push(m_BooleanPrototype); + if (m_StringPrototype) + stack.push(m_StringPrototype); + if (m_NumberPrototype) + stack.push(m_NumberPrototype); + if (m_DatePrototype) + stack.push(m_DatePrototype); + if (m_RegExpPrototype) + stack.push(m_RegExpPrototype); + if (m_ErrorPrototype) + stack.push(m_ErrorPrototype); + + if (m_EvalError) + stack.push(m_EvalError); + if (m_RangeError) + stack.push(m_RangeError); + if (m_ReferenceError) + stack.push(m_ReferenceError); + if (m_SyntaxError) + stack.push(m_SyntaxError); + if (m_TypeError) + stack.push(m_TypeError); + if (m_UriError) + stack.push(m_UriError); + + if (m_EvalErrorPrototype) + stack.push(m_EvalErrorPrototype); + if (m_RangeErrorPrototype) + stack.push(m_RangeErrorPrototype); + if (m_ReferenceErrorPrototype) + stack.push(m_ReferenceErrorPrototype); + if (m_SyntaxErrorPrototype) + stack.push(m_SyntaxErrorPrototype); + if (m_TypeErrorPrototype) + stack.push(m_TypeErrorPrototype); + if (m_UriErrorPrototype) + stack.push(m_UriErrorPrototype); } static bool printExceptions = false; diff --git a/JavaScriptCore/kjs/interpreter.h b/JavaScriptCore/kjs/interpreter.h index 3cb86c270b0..9f54d3a9bff 100644 --- a/JavaScriptCore/kjs/interpreter.h +++ b/JavaScriptCore/kjs/interpreter.h @@ -290,7 +290,7 @@ namespace KJS { * Called during the mark phase of the garbage collector. Subclasses * implementing custom mark methods must make sure to chain to this one. */ - virtual void mark(); + virtual void markRoots(MarkStack&); static bool shouldPrintExceptions(); static void setShouldPrintExceptions(bool); diff --git a/JavaScriptCore/kjs/list.cpp b/JavaScriptCore/kjs/list.cpp index eec703e5131..f60051f69fe 100644 --- a/JavaScriptCore/kjs/list.cpp +++ b/JavaScriptCore/kjs/list.cpp @@ -43,18 +43,15 @@ List::ListSet& List::markSet() return staticMarkSet; } -void List::markProtectedListsSlowCase() +void List::markProtectedListsSlowCase(MarkStack& stack) { ListSet::iterator end = markSet().end(); for (ListSet::iterator it = markSet().begin(); it != end; ++it) { List* list = *it; iterator end2 = list->end(); - for (iterator it2 = list->begin(); it2 != end2; ++it2) { - JSValue* v = *it2; - if (!v->marked()) - v->mark(); - } + for (iterator it2 = list->begin(); it2 != end2; ++it2) + stack.push(*it2); } } diff --git a/JavaScriptCore/kjs/list.h b/JavaScriptCore/kjs/list.h index b66e710ef14..4969b3ace0b 100644 --- a/JavaScriptCore/kjs/list.h +++ b/JavaScriptCore/kjs/list.h @@ -85,18 +85,18 @@ namespace KJS { const_iterator begin() const { return m_vector.begin(); } const_iterator end() const { return m_vector.end(); } - static void markProtectedLists() + static void markProtectedLists(MarkStack& stack) { if (!markSet().size()) return; - markProtectedListsSlowCase(); + markProtectedListsSlowCase(stack); } static const List& empty(); // Fast path for an empty list. private: static ListSet& markSet(); - static void markProtectedListsSlowCase(); + static void markProtectedListsSlowCase(MarkStack&); void expandAndAppend(JSValue*); diff --git a/JavaScriptCore/kjs/object.cpp b/JavaScriptCore/kjs/object.cpp index 13d5e655365..8514b0c0891 100644 --- a/JavaScriptCore/kjs/object.cpp +++ b/JavaScriptCore/kjs/object.cpp @@ -113,10 +113,8 @@ JSValue *JSObject::call(ExecState *exec, JSObject *thisObj, const List &args) // ------------------------------ JSObject ------------------------------------ -void JSObject::mark() +void JSObject::markChildren(MarkStack& stack) { - JSCell::mark(); - #if JAVASCRIPT_MARK_TRACING static int markStackDepth = 0; markStackDepth++; @@ -126,11 +124,8 @@ void JSObject::mark() printf("%s (%p)\n", className().UTF8String().c_str(), this); #endif - JSValue *proto = _proto; - if (!proto->marked()) - proto->mark(); - - _prop.mark(); + stack.push(_proto); + _prop.markChildren(stack); #if JAVASCRIPT_MARK_TRACING markStackDepth--; diff --git a/JavaScriptCore/kjs/object.h b/JavaScriptCore/kjs/object.h index 1f45f5eb0a2..531d0d6e564 100644 --- a/JavaScriptCore/kjs/object.h +++ b/JavaScriptCore/kjs/object.h @@ -27,6 +27,7 @@ #include "JSType.h" #include "CommonIdentifiers.h" +#include "MarkStack.h" #include "interpreter.h" #include "property_map.h" #include "property_slot.h" @@ -84,7 +85,7 @@ namespace KJS { virtual UString toString(ExecState *exec) const; virtual JSObject *toObject(ExecState *exec) const; - virtual void mark(); + virtual void markChildren(MarkStack&); JSObject *getGetter() { return getter; } void setGetter(JSObject *g) { getter = g; } @@ -111,7 +112,7 @@ namespace KJS { */ JSObject(); - virtual void mark(); + virtual void markChildren(MarkStack&); virtual JSType type() const; /** @@ -586,12 +587,11 @@ ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifie // FIXME: Put this function in a separate file named something like scope_chain_mark.h -- can't put it in scope_chain.h since it depends on JSObject. -inline void ScopeChain::mark() +inline void ScopeChain::markChildren(MarkStack& stack) { - for (ScopeChainNode *n = _node; n; n = n->next) { - JSObject *o = n->object; - if (!o->marked()) - o->mark(); + for (ScopeChainNode* n = _node; n; n = n->next) { + JSObject* o = n->object; + stack.push(o); } } diff --git a/JavaScriptCore/kjs/property_map.cpp b/JavaScriptCore/kjs/property_map.cpp index 45e391a6d4b..11c796b364d 100644 --- a/JavaScriptCore/kjs/property_map.cpp +++ b/JavaScriptCore/kjs/property_map.cpp @@ -622,25 +622,19 @@ void PropertyMap::remove(const Identifier& name) checkConsistency(); } -void PropertyMap::mark() const +void PropertyMap::markChildren(MarkStack& stack) const { if (!m_usingTable) { #if USE_SINGLE_ENTRY - if (m_singleEntryKey) { - JSValue* v = m_u.singleEntryValue; - if (!v->marked()) - v->mark(); - } + if (m_singleEntryKey) + stack.push(m_u.singleEntryValue); #endif return; } unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; i++) { - JSValue* v = m_u.table->entries()[i].value; - if (!v->marked()) - v->mark(); - } + for (unsigned i = 1; i <= entryCount; i++) + stack.push(m_u.table->entries()[i].value); } static int comparePropertyMapEntryIndices(const void* a, const void* b) diff --git a/JavaScriptCore/kjs/property_map.h b/JavaScriptCore/kjs/property_map.h index 82144efb55d..097e5b837b3 100644 --- a/JavaScriptCore/kjs/property_map.h +++ b/JavaScriptCore/kjs/property_map.h @@ -29,6 +29,7 @@ namespace KJS { class JSObject; class JSValue; + class MarkStack; class PropertyNameArray; struct PropertyMapEntry; @@ -59,7 +60,7 @@ namespace KJS { JSValue* get(const Identifier&, unsigned& attributes) const; JSValue** getLocation(const Identifier& name); - void mark() const; + void markChildren(MarkStack&) const; void getEnumerablePropertyNames(PropertyNameArray&) const; void save(SavedProperties&) const; diff --git a/JavaScriptCore/kjs/scope_chain.h b/JavaScriptCore/kjs/scope_chain.h index a10abcdbba0..eb2e89bbd42 100644 --- a/JavaScriptCore/kjs/scope_chain.h +++ b/JavaScriptCore/kjs/scope_chain.h @@ -82,7 +82,7 @@ namespace KJS { void push(const ScopeChain &); void pop(); - void mark(); + void markChildren(MarkStack&); #ifndef NDEBUG void print(); diff --git a/JavaScriptCore/kjs/string_object.cpp b/JavaScriptCore/kjs/string_object.cpp index c74f549c99f..c7722475519 100644 --- a/JavaScriptCore/kjs/string_object.cpp +++ b/JavaScriptCore/kjs/string_object.cpp @@ -129,6 +129,12 @@ void StringInstance::getPropertyNames(ExecState* exec, PropertyNameArray& proper return JSObject::getPropertyNames(exec, propertyNames); } +void StringInstance::markChildren(MarkStack& stack) +{ + JSObject::markChildren(stack); + stack.pushAtom(internalValue()); +} + // ------------------------------ StringPrototype --------------------------- const ClassInfo StringPrototype::info = { "String", &StringInstance::info, &stringTable }; /* Source for string_object.lut.h diff --git a/JavaScriptCore/kjs/string_object.h b/JavaScriptCore/kjs/string_object.h index ad3c52a6430..b295e2133e6 100644 --- a/JavaScriptCore/kjs/string_object.h +++ b/JavaScriptCore/kjs/string_object.h @@ -46,6 +46,7 @@ namespace KJS { static const ClassInfo info; StringImp* internalValue() const { return static_cast(JSWrapperObject::internalValue());} + virtual void markChildren(MarkStack& stack); private: bool inlineGetOwnPropertySlot(ExecState*, unsigned, PropertySlot&); diff --git a/JavaScriptCore/kjs/value.h b/JavaScriptCore/kjs/value.h index 5ebb5750d16..b826a408ecd 100644 --- a/JavaScriptCore/kjs/value.h +++ b/JavaScriptCore/kjs/value.h @@ -33,6 +33,7 @@ namespace KJS { class ExecState; class JSObject; class JSCell; +class MarkStack; struct ClassInfo; @@ -47,6 +48,7 @@ struct ClassInfo; class JSValue : Noncopyable { friend class JSCell; // so it can derive from this class friend class Collector; // so it can call asCell() + friend class MarkStack; // so it can call asCell() private: JSValue(); @@ -105,7 +107,7 @@ public: float toFloat(ExecState*) const; // Garbage collection. - void mark(); + void markChildren(MarkStack&); bool marked() const; static int32_t toInt32SlowCase(double, bool& ok); @@ -164,7 +166,7 @@ public: // Garbage collection. void *operator new(size_t); - virtual void mark(); + virtual void markChildren(MarkStack&); bool marked() const; }; @@ -290,9 +292,8 @@ inline bool JSCell::marked() const return Collector::isCellMarked(this); } -inline void JSCell::mark() +inline void JSCell::markChildren(MarkStack&) { - return Collector::markCell(this); } ALWAYS_INLINE JSCell* JSValue::asCell() @@ -406,10 +407,10 @@ inline bool JSValue::getTruncatedUInt32(uint32_t& v) const return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v); } -inline void JSValue::mark() +inline void JSValue::markChildren(MarkStack& stack) { - ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark() - asCell()->mark(); + ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling markChildren() + asCell()->markChildren(stack); } inline bool JSValue::marked() const diff --git a/JavaScriptGlue/ChangeLog b/JavaScriptGlue/ChangeLog index 65e4a690d8f..01221489ee4 100644 --- a/JavaScriptGlue/ChangeLog +++ b/JavaScriptGlue/ChangeLog @@ -1,3 +1,18 @@ +2007-11-28 Maciej Stachowiak + + Reviewed by Darin and Geoff. + + Fixups for JavaScriptCore mark stack. + + * JSObject.cpp: + (JSUserObject::Mark): + * JSObject.h: + * JSValueWrapper.cpp: + (JSValueWrapper::JSObjectMark): + * JSValueWrapper.h: + * UserObjectImp.cpp: + * UserObjectImp.h: + 2007-11-27 Anders Carlsson Build fix. diff --git a/JavaScriptGlue/JSObject.cpp b/JavaScriptGlue/JSObject.cpp index 1290cb34e5f..d4589366e97 100644 --- a/JavaScriptGlue/JSObject.cpp +++ b/JavaScriptGlue/JSObject.cpp @@ -122,11 +122,11 @@ UInt8 JSUserObject::Equal(JSBase* other) return result; } -void JSUserObject::Mark() +void JSUserObject::Mark(KJS::MarkStack& stack) { if (fMarkProc) { - fMarkProc(fData); + fMarkProc(stack, fData); } } diff --git a/JavaScriptGlue/JSObject.h b/JavaScriptGlue/JSObject.h index f0be22eb476..3d4b394db7d 100644 --- a/JavaScriptGlue/JSObject.h +++ b/JavaScriptGlue/JSObject.h @@ -32,7 +32,7 @@ #include "JSBase.h" #include "JSUtils.h" -typedef void (*JSObjectMarkProcPtr)(void *data); +typedef void (*JSObjectMarkProcPtr)(MarkStack&, void *data); JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int dataType); class JSUserObject : public JSBase { @@ -48,7 +48,7 @@ class JSUserObject : public JSBase { CFTypeRef CopyCFValue() const; virtual UInt8 Equal(JSBase* other); void *GetData(); - void Mark(); + void Mark(KJS::MarkStack&); int DataType() const { return fDataType; } private: diff --git a/JavaScriptGlue/JSValueWrapper.cpp b/JavaScriptGlue/JSValueWrapper.cpp index a101c8cf301..e3f80246287 100644 --- a/JavaScriptGlue/JSValueWrapper.cpp +++ b/JavaScriptGlue/JSValueWrapper.cpp @@ -230,11 +230,11 @@ CFTypeRef JSValueWrapper::JSObjectCopyCFValue(void *data) return result; } -void JSValueWrapper::JSObjectMark(void *data) +void JSValueWrapper::JSObjectMark(MarkStack& stack, void *data) { JSValueWrapper* ptr = (JSValueWrapper*)data; if (ptr) { - ptr->fValue->mark(); + ptr->fValue->markChildren(stack); } } diff --git a/JavaScriptGlue/JSValueWrapper.h b/JavaScriptGlue/JSValueWrapper.h index 5c3329755ee..a90f261a464 100644 --- a/JavaScriptGlue/JSValueWrapper.h +++ b/JavaScriptGlue/JSValueWrapper.h @@ -51,7 +51,7 @@ private: static void JSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue); static JSObjectRef JSObjectCallFunction(void *data, JSObjectRef thisObj, CFArrayRef args); static CFTypeRef JSObjectCopyCFValue(void *data); - static void JSObjectMark(void *data); + static void JSObjectMark(KJS::MarkStack&, void *data); }; #endif diff --git a/JavaScriptGlue/UserObjectImp.cpp b/JavaScriptGlue/UserObjectImp.cpp index 20c06c305e0..2517e52105b 100644 --- a/JavaScriptGlue/UserObjectImp.cpp +++ b/JavaScriptGlue/UserObjectImp.cpp @@ -406,9 +406,9 @@ UString UserObjectImp::toString(ExecState *exec) const return result; } -void UserObjectImp::mark() +void UserObjectImp::markChildren(MarkStack& stack) { - JSObject::mark(); + JSObject::markChildren(stack); if (fJSUserObject) - fJSUserObject->Mark(); + fJSUserObject->Mark(stack); } diff --git a/JavaScriptGlue/UserObjectImp.h b/JavaScriptGlue/UserObjectImp.h index 54e5ab637ed..0b995081c44 100644 --- a/JavaScriptGlue/UserObjectImp.h +++ b/JavaScriptGlue/UserObjectImp.h @@ -55,7 +55,7 @@ public: virtual double toNumber(ExecState *exec) const; virtual UString toString(ExecState *exec) const; - virtual void mark(); + virtual void markChildren(MarkStack& stack); JSUserObject *GetJSUserObject() const; private: diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 7400730483c..1058310baee 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,22 @@ +2007-11-28 Maciej Stachowiak + + Not reviewed. + + - Test cases for "Stack overflow crash in JavaScript garbage collector mark pass" + http://bugs.webkit.org/show_bug.cgi?id=12216 + + I have fixed this with the mark stack work. + + * fast/js/gc-breadth-2-expected.txt: Added. + * fast/js/gc-breadth-2.html: Added. + * fast/js/gc-breadth-expected.txt: Added. + * fast/js/gc-breadth.html: Added. + * fast/js/gc-depth-expected.txt: Added. + * fast/js/gc-depth.html: Added. + * fast/js/resources/gc-breadth-2.js: Added. + * fast/js/resources/gc-breadth.js: Added. + * fast/js/resources/gc-depth.js: Added. + 2007-11-27 Beth Dakin Reviewed by Oliver. diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index d0f8fe340d5..853f9befc3a 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,48 @@ +2007-11-28 Maciej Stachowiak + + Reviewed by Darin and Geoff. + + Implement mark stack. This version is not suitable for prime time because it makes a + huge allocation on every collect, and potentially makes marking of detached subtrees + slow. But it is a .2% - .4% speedup even without much tweaking. + + I replaced mark() methods with markChildren() as usual. One + optimization that is lost is avoiding walking detached DOM + subtrees more than once to mark them; since marking is not + recursive there's no obvious way to bracket operation on the tree + any more. + + * bindings/js/JSDocumentCustom.cpp: + (WebCore::JSDocument::markChildren): + * bindings/js/JSNodeCustom.cpp: + (WebCore::JSNode::markChildren): + * bindings/js/JSNodeFilterCondition.cpp: + * bindings/js/JSNodeFilterCondition.h: + * bindings/js/JSNodeFilterCustom.cpp: + (WebCore::JSNodeFilter::markChildren): + * bindings/js/JSNodeIteratorCustom.cpp: + (WebCore::JSNodeIterator::markChildren): + * bindings/js/JSTreeWalkerCustom.cpp: + (WebCore::JSTreeWalker::markChildren): + * bindings/js/JSXMLHttpRequest.cpp: + (KJS::JSXMLHttpRequest::markChildren): + * bindings/js/JSXMLHttpRequest.h: + * bindings/js/kjs_binding.cpp: + (KJS::ScriptInterpreter::markDOMNodesForDocument): + * bindings/js/kjs_binding.h: + * bindings/js/kjs_events.cpp: + (WebCore::JSUnprotectedEventListener::markChildren): + * bindings/js/kjs_events.h: + * bindings/js/kjs_window.cpp: + (KJS::Window::markChildren): + * bindings/js/kjs_window.h: + * bindings/scripts/CodeGeneratorJS.pm: + * dom/Node.cpp: + (WebCore::Node::Node): + * dom/Node.h: + * dom/NodeFilter.h: + * dom/NodeFilterCondition.h: + 2007-11-27 Alp Toker Reviewed by Mark Rowe. diff --git a/WebCore/bindings/js/JSDocumentCustom.cpp b/WebCore/bindings/js/JSDocumentCustom.cpp index 20957f0a9a7..423d44a5d43 100644 --- a/WebCore/bindings/js/JSDocumentCustom.cpp +++ b/WebCore/bindings/js/JSDocumentCustom.cpp @@ -37,10 +37,10 @@ namespace WebCore { using namespace KJS; -void JSDocument::mark() +void JSDocument::markChildren(MarkStack& stack) { - DOMObject::mark(); - ScriptInterpreter::markDOMNodesForDocument(static_cast(impl())); + DOMObject::markChildren(stack); + ScriptInterpreter::markDOMNodesForDocument(stack, static_cast(impl())); } JSValue* JSDocument::location(ExecState* exec) const diff --git a/WebCore/bindings/js/JSNodeCustom.cpp b/WebCore/bindings/js/JSNodeCustom.cpp index 6a5ce1c5e0d..f2ca61419fa 100644 --- a/WebCore/bindings/js/JSNodeCustom.cpp +++ b/WebCore/bindings/js/JSNodeCustom.cpp @@ -104,7 +104,7 @@ KJS::JSValue* JSNode::appendChild(KJS::ExecState* exec, const KJS::List& args) return KJS::jsNull(); } -void JSNode::mark() +void JSNode::markChildren(KJS::MarkStack& stack) { ASSERT(!marked()); @@ -113,7 +113,7 @@ void JSNode::mark() // Nodes in the document are kept alive by ScriptInterpreter::mark, // so we have no special responsibilities and can just call the base class here. if (node->inDocument()) { - DOMObject::mark(); + DOMObject::markChildren(stack); return; } @@ -123,31 +123,12 @@ void JSNode::mark() for (Node* current = m_impl.get(); current; current = current->parentNode()) root = current; - // If we're already marking this tree, then we can simply mark this wrapper - // by calling the base class; our caller is iterating the tree. - if (root->m_inSubtreeMark) { - DOMObject::mark(); - return; - } + // Mark the whole tree + for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) + if (JSNode* wrapper = KJS::ScriptInterpreter::getDOMNodeForDocument(m_impl->document(), nodeToMark)) + stack.push(wrapper); - // Mark the whole tree; use the global set of roots to avoid reentering. - root->m_inSubtreeMark = true; - for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) { - JSNode* wrapper = KJS::ScriptInterpreter::getDOMNodeForDocument(m_impl->document(), nodeToMark); - if (wrapper) { - if (!wrapper->marked()) - wrapper->mark(); - } else if (nodeToMark == node) { - // This is the case where the map from the document to wrappers has - // been cleared out, but a wrapper is being marked. For now, we'll - // let the rest of the tree of wrappers get collected, because we have - // no good way of finding them. Later we should test behavior of other - // browsers and see if we need to preserve other wrappers in this case. - if (!marked()) - mark(); - } - } - root->m_inSubtreeMark = false; + DOMObject::markChildren(stack); // Double check that we actually ended up marked. This assert caught problems in the past. ASSERT(marked()); diff --git a/WebCore/bindings/js/JSNodeFilterCondition.cpp b/WebCore/bindings/js/JSNodeFilterCondition.cpp index a48a61efb2e..2a0e2e2ef70 100644 --- a/WebCore/bindings/js/JSNodeFilterCondition.cpp +++ b/WebCore/bindings/js/JSNodeFilterCondition.cpp @@ -34,9 +34,9 @@ JSNodeFilterCondition::JSNodeFilterCondition(KJS::JSObject* filter) { } -void JSNodeFilterCondition::mark() +void JSNodeFilterCondition::markChildren(KJS::MarkStack& stack) { - m_filter->mark(); + stack.push(m_filter); } short JSNodeFilterCondition::acceptNode(Node* filterNode) const diff --git a/WebCore/bindings/js/JSNodeFilterCondition.h b/WebCore/bindings/js/JSNodeFilterCondition.h index bd172b94859..26c08f56116 100644 --- a/WebCore/bindings/js/JSNodeFilterCondition.h +++ b/WebCore/bindings/js/JSNodeFilterCondition.h @@ -31,7 +31,7 @@ namespace WebCore { public: JSNodeFilterCondition(KJS::JSObject* filter); virtual short acceptNode(Node*) const; - virtual void mark(); + virtual void markChildren(KJS::MarkStack&); protected: KJS::JSObject* m_filter; diff --git a/WebCore/bindings/js/JSNodeFilterCustom.cpp b/WebCore/bindings/js/JSNodeFilterCustom.cpp index 258059c510b..04481f7fa6c 100644 --- a/WebCore/bindings/js/JSNodeFilterCustom.cpp +++ b/WebCore/bindings/js/JSNodeFilterCustom.cpp @@ -32,10 +32,10 @@ namespace WebCore { -void JSNodeFilter::mark() + void JSNodeFilter::markChildren(KJS::MarkStack& stack) { - impl()->mark(); - DOMObject::mark(); + impl()->markChildren(stack); + DOMObject::markChildren(stack); } NodeFilter* toNodeFilter(KJS::JSValue* val) diff --git a/WebCore/bindings/js/JSNodeIteratorCustom.cpp b/WebCore/bindings/js/JSNodeIteratorCustom.cpp index deb0ffef525..189e70c5553 100644 --- a/WebCore/bindings/js/JSNodeIteratorCustom.cpp +++ b/WebCore/bindings/js/JSNodeIteratorCustom.cpp @@ -24,12 +24,12 @@ namespace WebCore { -void JSNodeIterator::mark() +void JSNodeIterator::markChildren(KJS::MarkStack& stack) { if (NodeFilter* filter = m_impl->filter()) - filter->mark(); + filter->markChildren(stack); - DOMObject::mark(); + DOMObject::markChildren(stack); } } diff --git a/WebCore/bindings/js/JSTreeWalkerCustom.cpp b/WebCore/bindings/js/JSTreeWalkerCustom.cpp index c73fe40acbf..47b5185c3bd 100644 --- a/WebCore/bindings/js/JSTreeWalkerCustom.cpp +++ b/WebCore/bindings/js/JSTreeWalkerCustom.cpp @@ -24,12 +24,12 @@ namespace WebCore { -void JSTreeWalker::mark() +void JSTreeWalker::markChildren(KJS::MarkStack& stack) { if (NodeFilter* filter = m_impl->filter()) - filter->mark(); + filter->markChildren(stack); - DOMObject::mark(); + DOMObject::markChildren(stack); } } diff --git a/WebCore/bindings/js/JSXMLHttpRequest.cpp b/WebCore/bindings/js/JSXMLHttpRequest.cpp index 5098785e310..d7345f06de9 100644 --- a/WebCore/bindings/js/JSXMLHttpRequest.cpp +++ b/WebCore/bindings/js/JSXMLHttpRequest.cpp @@ -170,18 +170,18 @@ void JSXMLHttpRequest::putValueProperty(ExecState* exec, int token, JSValue* val } } -void JSXMLHttpRequest::mark() +void JSXMLHttpRequest::markChildren(KJS::MarkStack& stack) { - DOMObject::mark(); + DOMObject::markChildren(stack); JSUnprotectedEventListener* onReadyStateChangeListener = static_cast(m_impl->onReadyStateChangeListener()); JSUnprotectedEventListener* onLoadListener = static_cast(m_impl->onLoadListener()); if (onReadyStateChangeListener) - onReadyStateChangeListener->mark(); + onReadyStateChangeListener->markChildren(stack); if (onLoadListener) - onLoadListener->mark(); + onLoadListener->markChildren(stack); typedef XMLHttpRequest::EventListenersMap EventListenersMap; typedef XMLHttpRequest::ListenerVector ListenerVector; @@ -189,7 +189,7 @@ void JSXMLHttpRequest::mark() for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) { for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter) { JSUnprotectedEventListener* listener = static_cast(vecIter->get()); - listener->mark(); + listener->markChildren(stack); } } } diff --git a/WebCore/bindings/js/JSXMLHttpRequest.h b/WebCore/bindings/js/JSXMLHttpRequest.h index 6afb608fc9d..e3f7e5ab3a7 100644 --- a/WebCore/bindings/js/JSXMLHttpRequest.h +++ b/WebCore/bindings/js/JSXMLHttpRequest.h @@ -57,7 +57,7 @@ public: virtual void put(ExecState*, const Identifier& propertyName, JSValue* value, int attr = None); void putValueProperty(ExecState*, int token, JSValue* value, int /*attr*/); virtual bool toBoolean(ExecState*) const { return true; } - virtual void mark(); + virtual void markChildren(MarkStack&); WebCore::XMLHttpRequest* impl() const { return m_impl.get(); } diff --git a/WebCore/bindings/js/kjs_binding.cpp b/WebCore/bindings/js/kjs_binding.cpp index 2dcc9fedd1b..ed7b4e3f208 100644 --- a/WebCore/bindings/js/kjs_binding.cpp +++ b/WebCore/bindings/js/kjs_binding.cpp @@ -210,7 +210,7 @@ void ScriptInterpreter::forgetAllDOMNodesForDocument(Document* document) delete map; } -void ScriptInterpreter::markDOMNodesForDocument(Document* doc) +void ScriptInterpreter::markDOMNodesForDocument(MarkStack& stack, Document* doc) { NodePerDocMap::iterator dictIt = domNodesPerDocument().find(doc); if (dictIt != domNodesPerDocument().end()) { @@ -225,9 +225,9 @@ void ScriptInterpreter::markDOMNodesForDocument(Document* doc) // otherwise reachable from JS. // However, image elements that aren't in the document are also // marked, if they are not done loading yet. - if (!jsNode->marked() && (node->inDocument() || (node->hasTagName(imgTag) && - !static_cast(node)->haveFiredLoadEvent()))) - jsNode->mark(); + if (node->inDocument() || (node->hasTagName(imgTag) && + !static_cast(node)->haveFiredLoadEvent())) + stack.push(jsNode); } } } diff --git a/WebCore/bindings/js/kjs_binding.h b/WebCore/bindings/js/kjs_binding.h index 06c8f72666f..c740225e41f 100644 --- a/WebCore/bindings/js/kjs_binding.h +++ b/WebCore/bindings/js/kjs_binding.h @@ -83,7 +83,7 @@ namespace KJS { static void forgetDOMNodeForDocument(WebCore::Document*, WebCore::Node*); static void forgetAllDOMNodesForDocument(WebCore::Document*); static void updateDOMNodeDocument(WebCore::Node*, WebCore::Document* oldDoc, WebCore::Document* newDoc); - static void markDOMNodesForDocument(WebCore::Document*); + static void markDOMNodesForDocument(MarkStack&, WebCore::Document*); WebCore::Frame* frame() const { return m_frame; } diff --git a/WebCore/bindings/js/kjs_events.cpp b/WebCore/bindings/js/kjs_events.cpp index 17297b9af92..e78c8c70d5b 100644 --- a/WebCore/bindings/js/kjs_events.cpp +++ b/WebCore/bindings/js/kjs_events.cpp @@ -187,10 +187,10 @@ void JSUnprotectedEventListener::clearWindowObj() m_win = 0; } -void JSUnprotectedEventListener::mark() +void JSUnprotectedEventListener::markChildren(KJS::MarkStack& stack) { - if (m_listener && !m_listener->marked()) - m_listener->mark(); + if (m_listener) + stack.push(m_listener); } #ifndef NDEBUG diff --git a/WebCore/bindings/js/kjs_events.h b/WebCore/bindings/js/kjs_events.h index 545e00246ef..52cfb5e63a2 100644 --- a/WebCore/bindings/js/kjs_events.h +++ b/WebCore/bindings/js/kjs_events.h @@ -57,7 +57,7 @@ namespace WebCore { virtual KJS::JSObject* listenerObj() const; virtual KJS::Window* windowObj() const; void clearWindowObj(); - virtual void mark(); + virtual void markChildren(KJS::MarkStack&); private: KJS::JSObject* m_listener; KJS::Window* m_win; diff --git a/WebCore/bindings/js/kjs_window.cpp b/WebCore/bindings/js/kjs_window.cpp index a123c07b69c..265a9541094 100644 --- a/WebCore/bindings/js/kjs_window.cpp +++ b/WebCore/bindings/js/kjs_window.cpp @@ -290,11 +290,11 @@ Location *Window::location() const } // reference our special objects during garbage collection -void Window::mark() +void Window::markChildren(KJS::MarkStack& stack) { - JSObject::mark(); - if (d->loc && !d->loc->marked()) - d->loc->mark(); + JSObject::markChildren(stack); + if (d->loc) + stack.push(d->loc); } static bool allowPopUp(ExecState *exec, Window *window) diff --git a/WebCore/bindings/js/kjs_window.h b/WebCore/bindings/js/kjs_window.h index d705b2622d9..d7b46ae5f8c 100644 --- a/WebCore/bindings/js/kjs_window.h +++ b/WebCore/bindings/js/kjs_window.h @@ -90,7 +90,7 @@ namespace KJS { * was called from. */ static Window* retrieveActive(ExecState*); - virtual void mark(); + virtual void markChildren(MarkStack&); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); JSValue *getValueProperty(ExecState *exec, int token) const; virtual void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None); diff --git a/WebCore/bindings/scripts/CodeGeneratorJS.pm b/WebCore/bindings/scripts/CodeGeneratorJS.pm index 6d185cfe222..a284db72461 100644 --- a/WebCore/bindings/scripts/CodeGeneratorJS.pm +++ b/WebCore/bindings/scripts/CodeGeneratorJS.pm @@ -366,7 +366,7 @@ sub GenerateHeader # Custom mark function if ($dataNode->extendedAttributes->{"CustomMarkFunction"}) { - push(@headerContent, " virtual void mark();\n\n"); + push(@headerContent, " virtual void markChildren(KJS::MarkStack&);\n\n"); } # Custom pushEventHandlerScope function diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp index dba01bd581e..c27100ab157 100644 --- a/WebCore/dom/Node.cpp +++ b/WebCore/dom/Node.cpp @@ -153,8 +153,7 @@ Node::Node(Document *doc) m_hovered(false), m_inActiveChain(false), m_inDetach(false), - m_dispatchingSimulatedEvent(false), - m_inSubtreeMark(false) + m_dispatchingSimulatedEvent(false) { #ifndef NDEBUG if (shouldIgnoreLeaks) diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h index 72886a0c6d9..1bdc0b0dbb3 100644 --- a/WebCore/dom/Node.h +++ b/WebCore/dom/Node.h @@ -484,9 +484,7 @@ protected: bool m_inDetach : 1; bool m_dispatchingSimulatedEvent : 1; -public: - bool m_inSubtreeMark : 1; - // 0 bits left + // 1 bit left private: Element* ancestorElement() const; diff --git a/WebCore/dom/NodeFilter.h b/WebCore/dom/NodeFilter.h index 66b175db252..359f2232849 100644 --- a/WebCore/dom/NodeFilter.h +++ b/WebCore/dom/NodeFilter.h @@ -30,6 +30,10 @@ #include "NodeFilterCondition.h" #include +namespace KJS { + class MarkStack; +} + namespace WebCore { class NodeFilter : public RefCounted { @@ -68,7 +72,7 @@ namespace WebCore { NodeFilter(NodeFilterCondition*); short acceptNode(Node*) const; - void mark() { m_condition->mark(); }; + void markChildren(KJS::MarkStack& stack) { m_condition->markChildren(stack); }; private: RefPtr m_condition; diff --git a/WebCore/dom/NodeFilterCondition.h b/WebCore/dom/NodeFilterCondition.h index 74fa2fa4307..4ee12fd2ca4 100644 --- a/WebCore/dom/NodeFilterCondition.h +++ b/WebCore/dom/NodeFilterCondition.h @@ -29,6 +29,10 @@ #include +namespace KJS { + class MarkStack; +} + namespace WebCore { class Node; @@ -37,7 +41,7 @@ namespace WebCore { public: virtual ~NodeFilterCondition() { } virtual short acceptNode(Node*) const; - virtual void mark() { } + virtual void markChildren(KJS::MarkStack&) { } }; } // namespace WebCore -- GitLab