JavaScriptCore:
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Nov 2007 10:08:09 +0000 (10:08 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Nov 2007 10:08:09 +0000 (10:08 +0000)
        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: https://svn.webkit.org/repository/webkit/trunk@28106 268f45cc-cd09-0410-ab3c-d52691b4dbfc

59 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/kjs/ExecState.cpp
JavaScriptCore/kjs/ExecState.h
JavaScriptCore/kjs/JSWrapperObject.cpp
JavaScriptCore/kjs/JSWrapperObject.h
JavaScriptCore/kjs/array_instance.cpp
JavaScriptCore/kjs/array_instance.h
JavaScriptCore/kjs/bool_object.cpp
JavaScriptCore/kjs/bool_object.h
JavaScriptCore/kjs/collector.cpp
JavaScriptCore/kjs/collector.h
JavaScriptCore/kjs/error_object.cpp
JavaScriptCore/kjs/error_object.h
JavaScriptCore/kjs/function.cpp
JavaScriptCore/kjs/function.h
JavaScriptCore/kjs/internal.cpp
JavaScriptCore/kjs/interpreter.cpp
JavaScriptCore/kjs/interpreter.h
JavaScriptCore/kjs/list.cpp
JavaScriptCore/kjs/list.h
JavaScriptCore/kjs/object.cpp
JavaScriptCore/kjs/object.h
JavaScriptCore/kjs/property_map.cpp
JavaScriptCore/kjs/property_map.h
JavaScriptCore/kjs/scope_chain.h
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/kjs/string_object.h
JavaScriptCore/kjs/value.h
JavaScriptGlue/ChangeLog
JavaScriptGlue/JSObject.cpp
JavaScriptGlue/JSObject.h
JavaScriptGlue/JSValueWrapper.cpp
JavaScriptGlue/JSValueWrapper.h
JavaScriptGlue/UserObjectImp.cpp
JavaScriptGlue/UserObjectImp.h
LayoutTests/ChangeLog
WebCore/ChangeLog
WebCore/bindings/js/JSDocumentCustom.cpp
WebCore/bindings/js/JSNodeCustom.cpp
WebCore/bindings/js/JSNodeFilterCondition.cpp
WebCore/bindings/js/JSNodeFilterCondition.h
WebCore/bindings/js/JSNodeFilterCustom.cpp
WebCore/bindings/js/JSNodeIteratorCustom.cpp
WebCore/bindings/js/JSTreeWalkerCustom.cpp
WebCore/bindings/js/JSXMLHttpRequest.cpp
WebCore/bindings/js/JSXMLHttpRequest.h
WebCore/bindings/js/kjs_binding.cpp
WebCore/bindings/js/kjs_binding.h
WebCore/bindings/js/kjs_events.cpp
WebCore/bindings/js/kjs_events.h
WebCore/bindings/js/kjs_window.cpp
WebCore/bindings/js/kjs_window.h
WebCore/bindings/scripts/CodeGeneratorJS.pm
WebCore/dom/Node.cpp
WebCore/dom/Node.h
WebCore/dom/NodeFilter.h
WebCore/dom/NodeFilterCondition.h

index 203f95fa4ab1b585945b8282e48d9f7c5e45c02b..dc7d94db82e7343c5e73049a15336f29ec086858 100644 (file)
@@ -1,3 +1,96 @@
+2007-11-28  Maciej Stachowiak  <mjs@apple.com>
+
+        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  <alp@atoker.com>
 
         Reviewed by Mark Rowe.
index 35f01b7b1e3c30ab63d1c8f762d5f916043ace3f..b33faef061518f91fe58813417c5ee8fe157c99e 100644 (file)
@@ -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
index 99a0e2f68b7f75b742b801ea1e664ca9f8706b85..d81d49566b63de8c6b8e4e460cc300b8450b2232 100644 (file)
@@ -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 */; };
                659126BC0BDD1728001921FB /* AllInOneFile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AllInOneFile.cpp; sourceTree = "<group>"; };
                6592C316098B7DE10003D4F6 /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = "<group>"; };
                6592C317098B7DE10003D4F6 /* VectorTraits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VectorTraits.h; sourceTree = "<group>"; };
+               65A8B8D80CF408E900DC7C27 /* MarkStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStack.h; sourceTree = "<group>"; };
                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 = "<group>"; };
                65B174BE09D1000200820339 /* chartables.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 30; path = chartables.c; sourceTree = "<group>"; };
                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 = "<group>"; };
                                F692A8680255597D01FF60F7 /* lookup.cpp */,
                                F692A8690255597D01FF60F7 /* lookup.h */,
                                F692A86A0255597D01FF60F7 /* math_object.cpp */,
+                               65A8B8D80CF408E900DC7C27 /* MarkStack.h */,
                                F692A86B0255597D01FF60F7 /* math_object.h */,
                                F692A86D0255597D01FF60F7 /* nodes.cpp */,
                                F692A86E0255597D01FF60F7 /* nodes.h */,
                                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 */,
index f828a691404b120f4ef073de6a72cd1823bd18ab..5a22e6959fdcf188422fa9fffd6780d7e7c9f4d7 100644 (file)
@@ -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)
index 5012350be7e837de778e5728227c7ea00c703c20..65f233f80ce8f827efa4b73d4981372e55f1030d 100644 (file)
@@ -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
index dd161f7afda88d751db71088f74ba815f6870b9b..36e7584a081982799ef5881142c12c81548e3a80 100644 (file)
 
 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
index 0a06c9fec3c8a7b65e97262426ef1c7ef39d8eb7..d51f0bd6cc05b7a1eaef9672b731fdcd09fc9250 100644 (file)
@@ -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())
     {
     }
     
index 282513232920408b4395f99688fd6ee7a465ad55..e940786b6fe39293831f434e9aee4e1d6e4b299d 100644 (file)
@@ -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);
     }
 }
 
index 913d0cdcf1455be07fbeecb861cf3387f2dfaf11..bb0a38e356ba9e1c6e51c9fd41506b8134384c58 100644 (file)
@@ -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;
index 916fe53ce555198321291424dbda3e83148407d4..a93c53d1351a8744ab3d6e03e8247a5107817de5 100644 (file)
@@ -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
index 3ab04a76f7e7d866a5778758fa8b1d4d0d08b895..2b8c0002fed358beaf3a2908c772847d35e55050 100644 (file)
@@ -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;
   };
 
index 7adfb8256a3aecf6ee1313c29ad2c806bf7d2934..34934e0f0838d8297ffbbb0692b169e44d7d7767 100644 (file)
@@ -26,6 +26,7 @@
 #include "ExecState.h"
 #include "internal.h"
 #include "list.h"
+#include "MarkStack.h"
 #include "value.h"
 #include <algorithm>
 #include <setjmp.h>
@@ -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<JSCell*>(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*)&regs, (void*)((char*)&regs + regSize));
+  markStackObjectsConservatively(stack, (void*)&regs, (void*)((char*)&regs + 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<JSCell*>(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<PrimaryHeap>(currentThreadIsMainThread);
   numLiveObjects += sweep<NumberHeap>(currentThreadIsMainThread);
   
index c8372f7d01c1aa69c95ea00078764fe2698a84de..60990a6c55d7af7de41476147566e34ba6704008 100644 (file)
 
 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) 
index 0697f107bd22d8f6c380dcb0de8eda9791b60e3f..69a6151790e5406e42859be1e42f5748a74fe383 100644 (file)
@@ -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();
-}
index 3e1ac8ae0850013e72368b53a46c95c58485a8fd..65154a76a5c84a8cca58e4d57698483953fd18df 100644 (file)
@@ -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:
index 1dc40a4028f4fb7a0b999163930a17f89c194b27..49ebd89242d7bae8b1fa82a5ede3ef4932734dc6 100644 (file)
@@ -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)
index 5657b1e71bf5861ea343368238bd6b44bc20d72c..392127e18a31202a953091f65bb8e6e65116d74f 100644 (file)
@@ -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; }
 
index 125244e2e66ed534153b0dd395d57baf332122e7..faf9f98a7fa1196042883fb85da0ff018c19299d 100644 (file)
@@ -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
index 2d381b20067425ae01d97c005b22df8858f0faea..eb2bbc81a16ae3b58a658315f4bcfc4fe7c8a90e 100644 (file)
@@ -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;
index 3cb86c270b0dcdee2b31e2488b1a8abbdef8609f..9f54d3a9bffe3a26db5910254fba4e4242212b1d 100644 (file)
@@ -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);
index eec703e5131313a6b5ed39906dde1184e72dcc6c..f60051f69fe04c54fd7d3e5abbabddb9d3ddecf6 100644 (file)
@@ -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);
     }
 }
 
index b66e710ef14084fccd6041eba2563ea49026aad0..4969b3ace0b726992f1c267016ef8fc19cc1ef2c 100644 (file)
@@ -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*);
 
index 13d5e6553658d11a668695b6c63e0604f0191d64..8514b0c0891bd8a8ef45e096c5af0d79daba7829 100644 (file)
@@ -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--;
index 1f45f5eb0a21357391f495c02c29638abb18fae5..531d0d6e564eae7c3d352ea3e71d5e0de69c5b87 100644 (file)
@@ -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);
     }
 }
 
index 45e391a6d4bca80662a78a01c1870348584703e3..11c796b364d4beb15bdcd6de4d26ed955787dbb3 100644 (file)
@@ -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)
index 82144efb55dc068cdab778472c6d4cf121f49999..097e5b837b3d3bce05884ce508377a9957dcc339 100644 (file)
@@ -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;
index a10abcdbba00eb2d903ff6113027ac3e514499ce..eb2e89bbd4258f1c31e8ca9a03eb436ab2aa195c 100644 (file)
@@ -82,7 +82,7 @@ namespace KJS {
         void push(const ScopeChain &);
         void pop();
         
-        void mark();
+        void markChildren(MarkStack&);
 
 #ifndef NDEBUG        
         void print();
index c74f549c99f1cda50e5ab62c804b7ce987ab5bab..c7722475519829f80347d9d9371697a138524e9b 100644 (file)
@@ -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
index ad3c52a64303e0445d0e4d979fedee2d68fae521..b295e2133e6a139f4b4eead14dbebc8cb4faf8f3 100644 (file)
@@ -46,6 +46,7 @@ namespace KJS {
     static const ClassInfo info;
 
     StringImp* internalValue() const { return static_cast<StringImp*>(JSWrapperObject::internalValue());}
+    virtual void markChildren(MarkStack& stack);
 
   private:
     bool inlineGetOwnPropertySlot(ExecState*, unsigned, PropertySlot&);
index 5ebb5750d164556c57529ec6f079d3f57cecce43..b826a408ecdc97cd7568bb6325a9d93e08800851 100644 (file)
@@ -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
index 65e4a690d8fbb04b28337e527afba2a2cee47e27..01221489ee4c51882351c35e0e8c471d7504f305 100644 (file)
@@ -1,3 +1,18 @@
+2007-11-28  Maciej Stachowiak  <mjs@apple.com>
+
+        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  <andersca@apple.com>
         
         Build fix.
index 1290cb34e5f4083d9effb1a4914beb00e366c4ec..d4589366e974534a7a6b222e53c5a47b0453062b 100644 (file)
@@ -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);
     }
 }
 
index f0be22eb47609794aba86d05f7b71bc04201a909..3d4b394db7dc72693eac7caa2e260fd3fe51e445 100644 (file)
@@ -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:
index a101c8cf301585d31e399e8bca1d2d2937a95b23..e3f8024628755c943a77c97f8f6c7da9454f178d 100644 (file)
@@ -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);
     }
 }
index 5c3329755eea36ff4c7d77ff074712979325239b..a90f261a464ff957035deffa8b63d0dec47232b7 100644 (file)
@@ -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
index 20c06c305e0807fd842682623dbf13fd896791ea..2517e52105bf8a1ea2ed396f4118aaedd638591a 100644 (file)
@@ -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);
 }
index 54e5ab637ed4d3f3f9a70d9a168e24a7464ba7a5..0b995081c44e5838c051147d27adf0c740cafd5f 100644 (file)
@@ -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:
index 7400730483caa279d9b9aabd9fdf97540d17fd40..1058310baee263b31a41c0782e3d80325e1fd88e 100644 (file)
@@ -1,3 +1,22 @@
+2007-11-28  Maciej Stachowiak  <mjs@apple.com>
+
+        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  <bdakin@apple.com>
 
         Reviewed by Oliver.
index d0f8fe340d58031c7c4c6226d1448c8637cb628a..853f9befc3ac1b6d107c26a724da14698f74ba4e 100644 (file)
@@ -1,3 +1,48 @@
+2007-11-28  Maciej Stachowiak  <mjs@apple.com>
+
+        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  <alp@atoker.com>
 
         Reviewed by Mark Rowe.
index 20957f0a9a7cb4845002e19c6074fa7f1ddb7c45..423d44a5d43a455c0aadfb3f3925f813de1afcda 100644 (file)
@@ -37,10 +37,10 @@ namespace WebCore {
 
 using namespace KJS;
 
-void JSDocument::mark()
+void JSDocument::markChildren(MarkStack& stack)
 {
-    DOMObject::mark();
-    ScriptInterpreter::markDOMNodesForDocument(static_cast<Document*>(impl()));
+    DOMObject::markChildren(stack);
+    ScriptInterpreter::markDOMNodesForDocument(stack, static_cast<Document*>(impl()));
 }
 
 JSValue* JSDocument::location(ExecState* exec) const
index 6a5ce1c5e0d4c603adb612ed35cc2412f5718dfb..f2ca61419fa7149c0d2ea614aaacb499c23e59c5 100644 (file)
@@ -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());
index a48a61efb2e1963966198bf3fd6bb158e92f1153..2a0e2e2ef70adb86ea58b0e38759d8f061008461 100644 (file)
@@ -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
index bd172b9485986a201ab68405e2446826bc618dfe..26c08f56116f2cfcd0e2b2ff29b92ba36599c24b 100644 (file)
@@ -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;
index 258059c510b5ee534ed2d0409ea7c1c97647884e..04481f7fa6c915d79a9ea925a9f2b9d7669412e4 100644 (file)
 
 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)
index deb0ffef525eddad8786c607216def05774dddc6..189e70c5553f9f0d8f15a1cc3a874c32a2a667aa 100644 (file)
 
 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);
 }
 
 }
index c73fe40acbf39a27a67c454dfbb349b8c1416371..47b5185c3bdecada137db2f7fadb5b7086997259 100644 (file)
 
 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);
 }
     
 }
index 5098785e3100d209f333359361b40ea384af6ead..d7345f06de90665f45c15a74799e0cb1f7b7707e 100644 (file)
@@ -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<JSUnprotectedEventListener*>(m_impl->onReadyStateChangeListener());
     JSUnprotectedEventListener* onLoadListener = static_cast<JSUnprotectedEventListener*>(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<JSUnprotectedEventListener*>(vecIter->get());
-            listener->mark();
+            listener->markChildren(stack);
         }
     }
 }
index 6afb608fc9db6c749f5dfc2fa93e077d40602b53..e3f7e5ab3a7dcc9cfb645d03d0f86bb4d406e5b7 100644 (file)
@@ -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(); }
 
index 2dcc9fedd1b2afa6e9a10a539f53b60e3acbb1d5..ed7b4e3f208410633535751c77e0bb9642b936b6 100644 (file)
@@ -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<HTMLImageElement*>(node)->haveFiredLoadEvent())))
-                jsNode->mark();
+            if (node->inDocument() || (node->hasTagName(imgTag) &&
+                                       !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()))
+                stack.push(jsNode);
         }
     }
 }
index 06c8f72666fe686b2867a0c48ef2765caf24ec3e..c740225e41f1c1aa43203abadf56b3c6e1173ede 100644 (file)
@@ -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; }
 
index 17297b9af926d32ac4dba39c80a95ad6e40af609..e78c8c70d5b1b55b991273496743a514bfedf621 100644 (file)
@@ -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
index 545e00246efbd83dcbdea889842b7ddec9d46556..52cfb5e63a2ac6679d441772b322592c0fd26386 100644 (file)
@@ -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;
index a123c07b69c3fa0050effdfa0cb72358bccbdc2e..265a95410948ce543552aea58c470be9fe1904b9 100644 (file)
@@ -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)
index d705b2622d9e362f4274c0f2c4d954a135c6570c..d7b46ae5f8c7af25d00191f2d3027ba53da3fc94 100644 (file)
@@ -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);
index 6d185cfe222da3e04a4086de40dd7eac45016389..a284db724614ca3d2f27bafb4d8699672df342cc 100644 (file)
@@ -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
index dba01bd581e76ecd3e46fec091a7b2091a9fb27b..c27100ab15744bec7b50ac6e4b2a869b1ae5b9b7 100644 (file)
@@ -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)
index 72886a0c6d997a323e70a748f83ba61f183c20a9..1bdc0b0dbb37b65e9b297a1187fbd069afc4bfb3 100644 (file)
@@ -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;
index 66b175db2525d16c0b46d77699b598784da2c17f..359f2232849ac33a20df5bc2fa75f1e1d4b0ea66 100644 (file)
 #include "NodeFilterCondition.h"
 #include <wtf/RefPtr.h>
 
+namespace KJS {
+    class MarkStack;
+}
+
 namespace WebCore {
 
     class NodeFilter : public RefCounted<NodeFilter> {
@@ -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<NodeFilterCondition> m_condition;
index 74fa2fa4307bc05f2c9dfbbd1c3f9c1289d18263..4ee12fd2ca475381d46696cc0b6ee035fe5194eb 100644 (file)
 
 #include <wtf/RefCounted.h>
 
+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