source: webkit/trunk/JavaScriptCore/kjs/internal.h@ 25625

Last change on this file since 25625 was 24633, checked in by mjs, 18 years ago

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:
  • Property svn:eol-style set to native
File size: 4.3 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
6 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#ifndef INTERNAL_H
26#define INTERNAL_H
27
28#include "JSType.h"
29#include "interpreter.h"
30#include "object.h"
31#include "protect.h"
32#include "scope_chain.h"
33#include "types.h"
34#include "ustring.h"
35
36#include <wtf/Noncopyable.h>
37
38#define I18N_NOOP(s) s
39
40namespace KJS {
41
42 class FunctionPrototype;
43
44 // ---------------------------------------------------------------------------
45 // Primitive impls
46 // ---------------------------------------------------------------------------
47
48 class StringImp : public JSCell {
49 public:
50 StringImp(const UString& v) : val(v) { Collector::reportExtraMemoryCost(v.cost()); }
51 enum HasOtherOwnerType { HasOtherOwner };
52 StringImp(const UString& value, HasOtherOwnerType) : val(value) { }
53 UString value() const { return val; }
54
55 JSType type() const { return StringType; }
56
57 JSValue *toPrimitive(ExecState *exec, JSType preferred = UnspecifiedType) const;
58 bool toBoolean(ExecState *exec) const;
59 double toNumber(ExecState *exec) const;
60 UString toString(ExecState *exec) const;
61 JSObject *toObject(ExecState *exec) const;
62
63 private:
64 UString val;
65 };
66
67 class NumberImp : public JSCell {
68 friend class ConstantValues;
69 friend JSValue *jsNumberCell(double);
70 public:
71 double value() const { return val; }
72
73 JSType type() const { return NumberType; }
74
75 JSValue *toPrimitive(ExecState *exec, JSType preferred = UnspecifiedType) const;
76 bool toBoolean(ExecState *exec) const;
77 double toNumber(ExecState *exec) const;
78 UString toString(ExecState *exec) const;
79 JSObject *toObject(ExecState *exec) const;
80
81 private:
82 NumberImp(double v) : val(v) { }
83
84 virtual bool getUInt32(uint32_t&) const;
85
86 double val;
87 };
88
89
90 /**
91 * @short The "label set" in Ecma-262 spec
92 */
93 class LabelStack : Noncopyable {
94 public:
95 LabelStack()
96 : tos(0)
97 {
98 }
99 ~LabelStack();
100
101 /**
102 * If id is not empty and is not in the stack already, puts it on top of
103 * the stack and returns true, otherwise returns false
104 */
105 bool push(const Identifier &id);
106 /**
107 * Is the id in the stack?
108 */
109 bool contains(const Identifier &id) const;
110 /**
111 * Removes from the stack the last pushed id (what else?)
112 */
113 void pop();
114
115 private:
116 struct StackElem {
117 Identifier id;
118 StackElem *prev;
119 };
120
121 StackElem *tos;
122 };
123
124
125 // ---------------------------------------------------------------------------
126 // Evaluation
127 // ---------------------------------------------------------------------------
128
129 struct AttachedInterpreter;
130 class DebuggerImp {
131 public:
132
133 DebuggerImp() {
134 interps = 0;
135 isAborted = false;
136 }
137
138 void abort() { isAborted = true; }
139 bool aborted() const { return isAborted; }
140
141 AttachedInterpreter *interps;
142 bool isAborted;
143 };
144
145 // helper function for toInteger, toInt32, toUInt32 and toUInt16
146 double roundValue(ExecState *, JSValue *);
147
148#ifndef NDEBUG
149 void printInfo(ExecState *exec, const char *s, JSValue *, int lineno = -1);
150#endif
151
152inline LabelStack::~LabelStack()
153{
154 StackElem *prev;
155 for (StackElem *e = tos; e; e = prev) {
156 prev = e->prev;
157 delete e;
158 }
159}
160
161inline void LabelStack::pop()
162{
163 if (StackElem *e = tos) {
164 tos = e->prev;
165 delete e;
166 }
167}
168
169} // namespace
170
171#endif // INTERNAL_H
Note: See TracBrowser for help on using the repository browser.