Commit d342e879 authored by mjs@apple.com's avatar mjs@apple.com

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
parent 61a95a0d
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> 2007-11-27 Alp Toker <alp@atoker.com>
Reviewed by Mark Rowe. Reviewed by Mark Rowe.
......
...@@ -122,10 +122,10 @@ __ZN3KJS11Interpreter17startTimeoutCheckEv ...@@ -122,10 +122,10 @@ __ZN3KJS11Interpreter17startTimeoutCheckEv
__ZN3KJS11Interpreter21shouldPrintExceptionsEv __ZN3KJS11Interpreter21shouldPrintExceptionsEv
__ZN3KJS11Interpreter24setShouldPrintExceptionsEb __ZN3KJS11Interpreter24setShouldPrintExceptionsEb
__ZN3KJS11Interpreter27resetGlobalObjectPropertiesEv __ZN3KJS11Interpreter27resetGlobalObjectPropertiesEv
__ZN3KJS11Interpreter4markEv
__ZN3KJS11Interpreter6s_hookE __ZN3KJS11Interpreter6s_hookE
__ZN3KJS11Interpreter8evaluateERKNS_7UStringEiPKNS_5UCharEiPNS_7JSValueE __ZN3KJS11Interpreter8evaluateERKNS_7UStringEiPKNS_5UCharEiPNS_7JSValueE
__ZN3KJS11Interpreter8evaluateERKNS_7UStringEiS3_PNS_7JSValueE __ZN3KJS11Interpreter8evaluateERKNS_7UStringEiS3_PNS_7JSValueE
__ZN3KJS11Interpreter9markRootsERNS_9MarkStackE
__ZN3KJS11InterpreterC1Ev __ZN3KJS11InterpreterC1Ev
__ZN3KJS11InterpreterC2Ev __ZN3KJS11InterpreterC2Ev
__ZN3KJS11InterpreterD1Ev __ZN3KJS11InterpreterD1Ev
...@@ -144,6 +144,7 @@ __ZN3KJS13ArrayInstance4infoE ...@@ -144,6 +144,7 @@ __ZN3KJS13ArrayInstance4infoE
__ZN3KJS13SavedBuiltinsC1Ev __ZN3KJS13SavedBuiltinsC1Ev
__ZN3KJS13SavedBuiltinsD1Ev __ZN3KJS13SavedBuiltinsD1Ev
__ZN3KJS13jsOwnedStringERKNS_7UStringE __ZN3KJS13jsOwnedStringERKNS_7UStringE
__ZN3KJS14StringInstance12markChildrenERNS_9MarkStackE
__ZN3KJS14StringInstance14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE __ZN3KJS14StringInstance14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS14StringInstance16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE __ZN3KJS14StringInstance16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3KJS14StringInstance18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE __ZN3KJS14StringInstance18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
...@@ -152,7 +153,6 @@ __ZN3KJS14StringInstance3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi ...@@ -152,7 +153,6 @@ __ZN3KJS14StringInstance3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi
__ZN3KJS14StringInstance4infoE __ZN3KJS14StringInstance4infoE
__ZN3KJS14StringInstanceC1EPNS_8JSObjectERKNS_7UStringE __ZN3KJS14StringInstanceC1EPNS_8JSObjectERKNS_7UStringE
__ZN3KJS14StringInstanceC2EPNS_8JSObjectERKNS_7UStringE __ZN3KJS14StringInstanceC2EPNS_8JSObjectERKNS_7UStringE
__ZN3KJS15JSWrapperObject4markEv
__ZN3KJS15SavedPropertiesC1Ev __ZN3KJS15SavedPropertiesC1Ev
__ZN3KJS15SavedPropertiesD1Ev __ZN3KJS15SavedPropertiesD1Ev
__ZN3KJS16RuntimeObjectImp4infoE __ZN3KJS16RuntimeObjectImp4infoE
...@@ -201,6 +201,7 @@ __ZN3KJS8Debugger9exceptionEPNS_9ExecStateEiiPNS_7JSValueE ...@@ -201,6 +201,7 @@ __ZN3KJS8Debugger9exceptionEPNS_9ExecStateEiiPNS_7JSValueE
__ZN3KJS8DebuggerC2Ev __ZN3KJS8DebuggerC2Ev
__ZN3KJS8DebuggerD2Ev __ZN3KJS8DebuggerD2Ev
__ZN3KJS8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE __ZN3KJS8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
__ZN3KJS8JSObject12markChildrenERNS_9MarkStackE
__ZN3KJS8JSObject12removeDirectERKNS_10IdentifierE __ZN3KJS8JSObject12removeDirectERKNS_10IdentifierE
__ZN3KJS8JSObject14callAsFunctionEPNS_9ExecStateEPS0_RKNS_4ListE __ZN3KJS8JSObject14callAsFunctionEPNS_9ExecStateEPS0_RKNS_4ListE
__ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE __ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
...@@ -212,7 +213,6 @@ __ZN3KJS8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPPNS_7JSValueE ...@@ -212,7 +213,6 @@ __ZN3KJS8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPPNS_7JSValueE
__ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi __ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi
__ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueEi __ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueEi
__ZN3KJS8JSObject4callEPNS_9ExecStateEPS0_RKNS_4ListE __ZN3KJS8JSObject4callEPNS_9ExecStateEPS0_RKNS_4ListE
__ZN3KJS8JSObject4markEv
__ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListE __ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListE
__ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListERKNS_10IdentifierERKNS_7UStringEi __ZN3KJS8JSObject9constructEPNS_9ExecStateERKNS_4ListERKNS_10IdentifierERKNS_7UStringEi
__ZN3KJS8JSObject9putDirectERKNS_10IdentifierEPNS_7JSValueEi __ZN3KJS8JSObject9putDirectERKNS_10IdentifierEPNS_7JSValueEi
......
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
6592C318098B7DE10003D4F6 /* Vector.h in Headers */ = {isa = PBXBuildFile; fileRef = 6592C316098B7DE10003D4F6 /* Vector.h */; settings = {ATTRIBUTES = (Private, ); }; }; 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, ); }; }; 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, ); }; }; 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 */; }; 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 */; }; 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 */; }; 65B174F609D100FA00820339 /* number_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B174F209D100FA00820339 /* number_object.lut.h */; };
...@@ -510,6 +511,7 @@ ...@@ -510,6 +511,7 @@
659126BC0BDD1728001921FB /* AllInOneFile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AllInOneFile.cpp; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; };
...@@ -1008,6 +1010,7 @@ ...@@ -1008,6 +1010,7 @@
F692A8680255597D01FF60F7 /* lookup.cpp */, F692A8680255597D01FF60F7 /* lookup.cpp */,
F692A8690255597D01FF60F7 /* lookup.h */, F692A8690255597D01FF60F7 /* lookup.h */,
F692A86A0255597D01FF60F7 /* math_object.cpp */, F692A86A0255597D01FF60F7 /* math_object.cpp */,
65A8B8D80CF408E900DC7C27 /* MarkStack.h */,
F692A86B0255597D01FF60F7 /* math_object.h */, F692A86B0255597D01FF60F7 /* math_object.h */,
F692A86D0255597D01FF60F7 /* nodes.cpp */, F692A86D0255597D01FF60F7 /* nodes.cpp */,
F692A86E0255597D01FF60F7 /* nodes.h */, F692A86E0255597D01FF60F7 /* nodes.h */,
...@@ -1170,6 +1173,7 @@ ...@@ -1170,6 +1173,7 @@
148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */, 148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */,
65F340940CD6C1C000C0CA8B /* LocalStorage.h in Headers */, 65F340940CD6C1C000C0CA8B /* LocalStorage.h in Headers */,
5DBD18B00C5401A700C15EAE /* MallocZoneSupport.h in Headers */, 5DBD18B00C5401A700C15EAE /* MallocZoneSupport.h in Headers */,
65A8B8DB0CF408F400DC7C27 /* MarkStack.h in Headers */,
BCF655590A2049710038A194 /* MathExtras.h in Headers */, BCF655590A2049710038A194 /* MathExtras.h in Headers */,
932F5B840822A1C700736975 /* NP_jsobject.h in Headers */, 932F5B840822A1C700736975 /* NP_jsobject.h in Headers */,
9303F56A0991190000AD71B8 /* Noncopyable.h in Headers */, 9303F56A0991190000AD71B8 /* Noncopyable.h in Headers */,
......
...@@ -88,10 +88,10 @@ ExecState::~ExecState() ...@@ -88,10 +88,10 @@ ExecState::~ExecState()
m_interpreter->setCurrentExec(m_savedExecState); m_interpreter->setCurrentExec(m_savedExecState);
} }
void ExecState::mark() void ExecState::markChildren(MarkStack& stack)
{ {
for (ExecState* exec = this; exec; exec = exec->m_callingExecState) for (ExecState* exec = this; exec; exec = exec->m_callingExecState)
exec->m_scopeChain.mark(); exec->m_scopeChain.markChildren(stack);
} }
void ExecState::setGlobalObject(JSGlobalObject* globalObject) void ExecState::setGlobalObject(JSGlobalObject* globalObject)
......
...@@ -100,7 +100,7 @@ namespace KJS { ...@@ -100,7 +100,7 @@ namespace KJS {
void setGlobalObject(JSGlobalObject*); void setGlobalObject(JSGlobalObject*);
void mark(); void markChildren(MarkStack&);
// This is a workaround to avoid accessing the global variables for these identifiers in // 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 // important property lookup functions, to avoid taking PIC branches in Mach-O binaries
......
...@@ -24,11 +24,10 @@ ...@@ -24,11 +24,10 @@
namespace KJS { namespace KJS {
void JSWrapperObject::mark() void JSWrapperObject::markChildren(MarkStack& stack)
{ {
JSObject::mark(); JSObject::markChildren(stack);
if (m_internalValue && !m_internalValue->marked()) stack.pushAtom(m_internalValue);
m_internalValue->mark();
} }
} // namespace KJS } // namespace KJS
...@@ -56,7 +56,7 @@ namespace KJS { ...@@ -56,7 +56,7 @@ namespace KJS {
*/ */
void setInternalValue(JSValue* v); void setInternalValue(JSValue* v);
virtual void mark(); virtual void markChildren(MarkStack& stack);
private: private:
JSValue* m_internalValue; JSValue* m_internalValue;
...@@ -64,7 +64,7 @@ namespace KJS { ...@@ -64,7 +64,7 @@ namespace KJS {
inline JSWrapperObject::JSWrapperObject(JSValue* proto) inline JSWrapperObject::JSWrapperObject(JSValue* proto)
: JSObject(proto) : JSObject(proto)
, m_internalValue(0) , m_internalValue(jsNull())
{ {
} }
......
...@@ -402,26 +402,23 @@ void ArrayInstance::setLength(unsigned newLength) ...@@ -402,26 +402,23 @@ void ArrayInstance::setLength(unsigned newLength)
m_length = newLength; m_length = newLength;
} }
void ArrayInstance::mark() void ArrayInstance::markChildren(MarkStack& stack)
{ {
JSObject::mark(); JSObject::markChildren(stack);
ArrayStorage* storage = m_storage; ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(m_length, m_vectorLength); unsigned usedVectorLength = min(m_length, m_vectorLength);
for (unsigned i = 0; i < usedVectorLength; ++i) { for (unsigned i = 0; i < usedVectorLength; ++i) {
JSValue* value = storage->m_vector[i]; JSValue* value = storage->m_vector[i];
if (value && !value->marked()) if (value)
value->mark(); stack.push(value);
} }
if (SparseArrayValueMap* map = storage->m_sparseValueMap) { if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end(); SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
JSValue* value = it->second; stack.push(it->second);
if (!value->marked())
value->mark();
}
} }
} }
......
...@@ -42,7 +42,7 @@ namespace KJS { ...@@ -42,7 +42,7 @@ namespace KJS {
virtual bool deleteProperty(ExecState *, unsigned propertyName); virtual bool deleteProperty(ExecState *, unsigned propertyName);
virtual void getPropertyNames(ExecState*, PropertyNameArray&); virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void mark(); virtual void markChildren(MarkStack&);
virtual const ClassInfo* classInfo() const { return &info; } virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info; static const ClassInfo info;
......
...@@ -38,6 +38,12 @@ BooleanInstance::BooleanInstance(JSObject *proto) ...@@ -38,6 +38,12 @@ BooleanInstance::BooleanInstance(JSObject *proto)
{ {
} }
void BooleanInstance::markChildren(MarkStack& stack)
{
JSObject::markChildren(stack);
ASSERT(JSImmediate::isImmediate(internalValue()));
}
// ------------------------------ BooleanPrototype -------------------------- // ------------------------------ BooleanPrototype --------------------------
// ECMA 15.6.4 // ECMA 15.6.4
......
...@@ -32,6 +32,7 @@ namespace KJS { ...@@ -32,6 +32,7 @@ namespace KJS {
BooleanInstance(JSObject *proto); BooleanInstance(JSObject *proto);
virtual const ClassInfo *classInfo() const { return &info; } virtual const ClassInfo *classInfo() const { return &info; }
virtual void markChildren(MarkStack& stack);
static const ClassInfo info; static const ClassInfo info;
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "ExecState.h" #include "ExecState.h"
#include "internal.h" #include "internal.h"
#include "list.h" #include "list.h"
#include "MarkStack.h"
#include "value.h" #include "value.h"
#include <algorithm> #include <algorithm>
#include <setjmp.h> #include <setjmp.h>
...@@ -277,6 +278,8 @@ collect: ...@@ -277,6 +278,8 @@ collect:
targetBlock = (Block*)allocateBlock(); targetBlock = (Block*)allocateBlock();
targetBlock->freeList = targetBlock->cells; targetBlock->freeList = targetBlock->cells;
if (heapType == PrimaryHeap)
targetBlock->mayHaveRefs = 1;
targetBlockUsedCells = 0; targetBlockUsedCells = 0;
heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock; heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock;
heap.usedBlocks = usedBlocks + 1; heap.usedBlocks = usedBlocks + 1;
...@@ -479,7 +482,14 @@ void Collector::registerThread() ...@@ -479,7 +482,14 @@ void Collector::registerThread()
// cell size needs to be a power of two for this to be valid // 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) #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) { if (start > end) {
void* tmp = start; void* tmp = start;
...@@ -521,8 +531,8 @@ void Collector::markStackObjectsConservatively(void *start, void *end) ...@@ -521,8 +531,8 @@ void Collector::markStackObjectsConservatively(void *start, void *end)
if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
if (((CollectorCell*)xAsBits)->u.freeCell.zeroIfFree != 0) { if (((CollectorCell*)xAsBits)->u.freeCell.zeroIfFree != 0) {
JSCell* imp = reinterpret_cast<JSCell*>(xAsBits); JSCell* imp = reinterpret_cast<JSCell*>(xAsBits);
if (!imp->marked()) stack.push(imp);
imp->mark(); drainMarkStack(stack);
} }
break; break;
} }
...@@ -533,7 +543,7 @@ void Collector::markStackObjectsConservatively(void *start, void *end) ...@@ -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 // setjmp forces volatile registers onto the stack
jmp_buf registers; jmp_buf registers;
...@@ -550,7 +560,7 @@ void Collector::markCurrentThreadConservatively() ...@@ -550,7 +560,7 @@ void Collector::markCurrentThreadConservatively()
void* stackPointer = &dummy; void* stackPointer = &dummy;
void* stackBase = currentThreadStackBase(); void* stackBase = currentThreadStackBase();
markStackObjectsConservatively(stackPointer, stackBase); markStackObjectsConservatively(stack, stackPointer, stackBase);
} }
#if USE(MULTIPLE_THREADS) #if USE(MULTIPLE_THREADS)
...@@ -693,7 +703,7 @@ static inline void* otherThreadStackBase(const PlatformThreadRegisters& regs, Co ...@@ -693,7 +703,7 @@ static inline void* otherThreadStackBase(const PlatformThreadRegisters& regs, Co
#endif #endif
} }
void Collector::markOtherThreadConservatively(Thread* thread) void Collector::markOtherThreadConservatively(MarkStack& stack, Thread* thread)
{ {
suspendThread(thread->platformThread); suspendThread(thread->platformThread);
...@@ -701,25 +711,25 @@ void Collector::markOtherThreadConservatively(Thread* thread) ...@@ -701,25 +711,25 @@ void Collector::markOtherThreadConservatively(Thread* thread)
size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
// mark the thread's registers // 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* stackPointer = otherThreadStackPointer(regs);
void* stackBase = otherThreadStackBase(regs, thread); void* stackBase = otherThreadStackBase(regs, thread);
markStackObjectsConservatively(stackPointer, stackBase); markStackObjectsConservatively(stack, stackPointer, stackBase);
resumeThread(thread->platformThread); resumeThread(thread->platformThread);
} }
#endif #endif
void Collector::markStackObjectsConservatively() void Collector::markStackObjectsConservatively(MarkStack& stack)
{ {
markCurrentThreadConservatively(); markCurrentThreadConservatively(stack);
#if USE(MULTIPLE_THREADS) #if USE(MULTIPLE_THREADS)
for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) { for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) {
if (!pthread_equal(thread->posixThread, pthread_self())) { if (!pthread_equal(thread->posixThread, pthread_self())) {
markOtherThreadConservatively(thread); markOtherThreadConservatively(stack, thread);
} }
} }
#endif #endif
...@@ -771,18 +781,17 @@ void Collector::collectOnMainThreadOnly(JSValue* value) ...@@ -771,18 +781,17 @@ void Collector::collectOnMainThreadOnly(JSValue* value)
++mainThreadOnlyObjectCount; ++mainThreadOnlyObjectCount;
} }
void Collector::markProtectedObjects() void Collector::markProtectedObjects(MarkStack& stack)
{ {
ProtectCountSet& protectedValues = KJS::protectedValues(); ProtectCountSet& protectedValues = KJS::protectedValues();
ProtectCountSet::iterator end = protectedValues.end(); ProtectCountSet::iterator end = protectedValues.end();
for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) { for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) {
JSCell *val = it->first; stack.push(it->first);
if (!val->marked()) drainMarkStack(stack);
val->mark();
} }
} }
void Collector::markMainThreadOnlyObjects() void Collector::markMainThreadOnlyObjects(MarkStack& stack)
{ {
#if USE(MULTIPLE_THREADS) #if USE(MULTIPLE_THREADS)
ASSERT(!onMainThread()); ASSERT(!onMainThread());
...@@ -814,7 +823,8 @@ void Collector::markMainThreadOnlyObjects() ...@@ -814,7 +823,8 @@ void Collector::markMainThreadOnlyObjects()
if (curBlock->collectOnMainThreadOnly.get(i)) { if (curBlock->collectOnMainThreadOnly.get(i)) {
if (!curBlock->marked.get(i)) { if (!curBlock->marked.get(i)) {
JSCell* imp = reinterpret_cast<JSCell*>(cell); JSCell* imp = reinterpret_cast<JSCell*>(cell);
imp->mark(); stack.push(imp);
drainMarkStack(stack);
} }
if (++count == mainThreadOnlyObjectCount) if (++count == mainThreadOnlyObjectCount)
return; return;
...@@ -950,9 +960,14 @@ bool Collector::collect() ...@@ -950,9 +960,14 @@ bool Collector::collect()
// MARK: first mark all referenced objects recursively starting out from the set of root objects // 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);