JavaScriptCore:
authormjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Jul 2007 21:50:00 +0000 (21:50 +0000)
committermjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Jul 2007 21:50:00 +0000 (21:50 +0000)
commitff6ccb4af21dd991ca8c92d5e996851ecdfabe97
tree840b6e370620280a5b5f2d5484e1c2abc362f8c5
parentfbc424b637b443fc915177b4803589359e1489cf
JavaScriptCore:

        Reviewed by Darin.

        - JavaScriptCore part of fix for <rdar://problem/5300291> Optimize GC to reclaim big, temporary objects (like XMLHttpRequest.responseXML) quickly

        Also, as a side effect of optimizations included in this patch:
        - 7% speedup on JavaScript iBench
        - 4% speedup on "Celtic Kane" JS benchmark

        The basic idea is explained in a big comment in collector.cpp. When unusually
        large objecs are allocated, we push the next GC closer on the assumption that
        most objects are short-lived.

        I also did the following two optimizations in the course of tuning
        this not to be a performance regression:

        1) Change UString::Rep to hold a self-pointer as the baseString in
        the unshared case, instead of a null pointer; this removes a
        number of null checks in hot code because many places already
        wanted to use the rep itself or the baseString as appropriate.

        2) Avoid creating duplicate StringImpls when creating a
        StringInstance (the object wrapper for a JS string) or calling
        their methods. Since a temporary wrapper object is made every time
        a string method is called, this resulted in two useless extra
        StringImpls being allocated for no reason whenever a String method
        was invoked on a string value. Now we bypass those.

        * kjs/collector.cpp:
        (KJS::):
        (KJS::Collector::recordExtraCost): Basics of the extra cost mechanism.
        (KJS::Collector::allocate): ditto
        (KJS::Collector::collect): ditto
        * kjs/collector.h:
        (KJS::Collector::reportExtraMemoryCost): ditto
        * kjs/array_object.cpp:
        (ArrayInstance::ArrayInstance): record extra cost
        * kjs/internal.cpp:
        (KJS::StringImp::toObject): don't create a whole new StringImpl just
        to be the internal value of a StringInstance! StringImpls are immutable
        so there's no point tot his.
        * kjs/internal.h:
        (KJS::StringImp::StringImp): report extra cost
        * kjs/string_object.cpp:
        (KJS::StringInstance::StringInstance): new version that takes a StringImp
        (KJS::StringProtoFunc::callAsFunction): don't create a whole new StringImpl
        just to convert self to string! we already have one in the internal value
        * kjs/string_object.h: report extra cost
        * kjs/ustring.cpp: All changes to handle baseString being self instead of null in the
        unshared case.
        (KJS::):
        (KJS::UString::Rep::create):
        (KJS::UString::Rep::destroy):
        (KJS::UString::usedCapacity):
        (KJS::UString::usedPreCapacity):
        (KJS::UString::expandCapacity):
        (KJS::UString::expandPreCapacity):
        (KJS::UString::UString):
        (KJS::UString::append):
        (KJS::UString::operator=):
        (KJS::UString::copyForWriting):
        * kjs/ustring.h:
        (KJS::UString::Rep::baseIsSelf): new method, now that baseString is
        self instead of null in the unshared case we can't just null check.
        (KJS::UString::Rep::data): adjusted as mentioned above
        (KJS::UString::cost): new method to compute the cost for a UString, for
        use by StringImpl.

        * kjs/value.cpp:
        (KJS::jsString): style fixups.
        (KJS::jsOwnedString): new method, use this for strings allocated from UStrings
        held by the parse tree. Tracking their cost as part of string cost is pointless,
        because garbage collecting them will not actually free the relevant string buffer.
        * kjs/value.h: prototyped jsOwnedString.
        * kjs/nodes.cpp:
        (StringNode::evaluate): use jsOwnedString as appropriate
        (RegExpNode::evaluate): ditto
        (PropertyNameNode::evaluate): ditto
        (ForInNode::execute): ditto

        * JavaScriptCore.exp: Exported some new symbols.

WebCore:

        Reviewed by Darin.

        - fixed <rdar://problem/5300291> Optimize GC to reclaim big, temporary objects (like XMLHttpRequest.responseXML) quickly

        With this plus related JavaScriptCore changes, a number of XMLHttpRequest situations that
        result in huge data sets are addressed, including a single huge responseXML on an XMR done
        repeatedly, or accessing responseText repeatedly during loading of a single large XHR.

        In addition to the GC changes in JavaScriptCore, I changed responseText to be stored as a
        KJS::UString instead of a WebCore::String so that the JavaScript responseText value can
        share the buffer (indeed multiple intermediate responseTexts can share its buffer).

        First of all, here's some manual test cases that will each blow out the process VM without this fix,
        but will settle into decent steady state with.

        * manual-tests/memory: Added.
        * manual-tests/memory/MessageUidsAlreadyDownloaded2: Added.
        * manual-tests/memory/string-growth.html: Added.
        * manual-tests/memory/xhr-multiple-requests-responseText.html: Added.
        * manual-tests/memory/xhr-multiple-requests-responseXML.html: Added.
        * manual-tests/memory/xhr-multiple-requests.html: Added.
        * manual-tests/memory/xhr-repeated-string-access.xml: Added.

        And here's the actual code changes:

        * WebCore.xcodeproj/project.pbxproj:
        * bindings/js/JSDocumentCustom.cpp:
        (WebCore::toJS): Record extra cost if the document is frameless (counting the nodes
        doesn't make a measurable performance difference here in any case I could find)
        * bindings/js/JSXMLHttpRequest.cpp:
        (KJS::JSXMLHttpRequest::getValueProperty): Adjust for the fact that ressponseText
        is now stored as a UString.
        * bindings/js/kjs_binding.cpp:
        (KJS::jsOwnedStringOrNull): New helper.
        * bindings/js/kjs_binding.h:
        * xml/XMLHttpRequest.cpp:
        (WebCore::XMLHttpRequest::getResponseText): It's a UString!
        (WebCore::XMLHttpRequest::getResponseXML): handle the fact that m_responseText
        is a UString.
        (WebCore::XMLHttpRequest::XMLHttpRequest): ditto.
        (WebCore::XMLHttpRequest::abort): call dropProtection
        (WebCore::XMLHttpRequest::didFinishLoading): call dropProtection
        (WebCore::XMLHttpRequest::dropProtection): after removing our GC protection,
        report extra cost of this XHR's responseText buffer.
        * xml/XMLHttpRequest.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@24633 268f45cc-cd09-0410-ab3c-d52691b4dbfc
27 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/kjs/array_object.cpp
JavaScriptCore/kjs/collector.cpp
JavaScriptCore/kjs/collector.h
JavaScriptCore/kjs/internal.cpp
JavaScriptCore/kjs/internal.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/kjs/string_object.h
JavaScriptCore/kjs/ustring.cpp
JavaScriptCore/kjs/ustring.h
JavaScriptCore/kjs/value.cpp
JavaScriptCore/kjs/value.h
WebCore/ChangeLog
WebCore/bindings/js/JSDocumentCustom.cpp
WebCore/bindings/js/JSXMLHttpRequest.cpp
WebCore/bindings/js/kjs_binding.cpp
WebCore/bindings/js/kjs_binding.h
WebCore/manual-tests/memory/MessageUidsAlreadyDownloaded2 [new file with mode: 0644]
WebCore/manual-tests/memory/string-growth.html [new file with mode: 0644]
WebCore/manual-tests/memory/xhr-multiple-requests-responseText.html [new file with mode: 0644]
WebCore/manual-tests/memory/xhr-multiple-requests-responseXML.html [new file with mode: 0644]
WebCore/manual-tests/memory/xhr-multiple-requests.html [new file with mode: 0644]
WebCore/manual-tests/memory/xhr-repeated-string-access.xml [new file with mode: 0644]
WebCore/xml/XMLHttpRequest.cpp
WebCore/xml/XMLHttpRequest.h