Ignore:
Timestamp:
Jul 25, 2007, 2:50:00 PM (18 years ago)
Author:
mjs
Message:

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


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:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/JavaScriptCore.exp

    r24106 r24633  
    186186__ZN3KJS8Bindings23convertObjcValueToValueEPNS_9ExecStateEPvNS0_13ObjcValueTypeEPNS0_10RootObjectE
    187187__ZN3KJS8Bindings23convertValueToObjcValueEPNS_9ExecStateEPNS_7JSValueENS0_13ObjcValueTypeE
    188 __ZNK3KJS8Bindings8Instance10rootObjectEv
    189188__ZN3KJS8Bindings8Instance18didExecuteFunctionEv
    190189__ZN3KJS8Bindings8Instance21setDidExecuteFunctionEPFvPNS_9ExecStateEPNS_8JSObjectEE
     
    212211__ZN3KJS8jsStringEPKc
    213212__ZN3KJS8jsStringERKNS_7UStringE
     213__ZN3KJS13jsOwnedStringERKNS_7UStringE
    214214__ZN3KJS9Collector15numInterpretersEv
     215__ZN3KJS9Collector15recordExtraCostEm
    215216__ZN3KJS9Collector19numProtectedObjectsEv
    216217__ZN3KJS9Collector20rootObjectTypeCountsEv
     
    258259__ZNK3KJS7UString8toUInt32EPbb
    259260__ZNK3KJS8Bindings10RootObject11interpreterEv
     261__ZNK3KJS8Bindings8Instance10rootObjectEv
    260262__ZNK3KJS8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
    261263__ZNK3KJS8JSObject12defaultValueEPNS_9ExecStateENS_6JSTypeE
Note: See TracChangeset for help on using the changeset viewer.