source: webkit/trunk/JavaScriptCore/runtime/JSString.cpp@ 51964

Last change on this file since 51964 was 51964, checked in by [email protected], 15 years ago

https://bugs.webkit.org/show_bug.cgi?id=32367
Add support for short Ropes (up to 3 entries) inline within JSString.
(rather than externally allocating an object to hold the rope).
Switch jsAdd of (JSString* + JSString*) to now make use of Ropes.

Reviewed by Oliver Hunt & Mark Rowe.

~1% progression on Sunspidey.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileCTIMachineTrampolines):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • runtime/JSString.cpp:

(JSC::JSString::resolveRope):
(JSC::JSString::toBoolean):
(JSC::JSString::getStringPropertyDescriptor):

  • runtime/JSString.h:

(JSC::JSString::Rope::Fiber::deref):
(JSC::JSString::Rope::Fiber::ref):
(JSC::JSString::Rope::Fiber::refAndGetLength):
(JSC::JSString::Rope::append):
(JSC::JSString::JSString):
(JSC::JSString::~JSString):
(JSC::JSString::value):
(JSC::JSString::tryGetValue):
(JSC::JSString::length):
(JSC::JSString::canGetIndex):
(JSC::JSString::appendStringInConstruct):
(JSC::JSString::appendValueInConstructAndIncrementLength):
(JSC::JSString::isRope):
(JSC::JSString::string):
(JSC::JSString::ropeLength):
(JSC::JSString::getStringPropertySlot):

  • runtime/Operations.h:

(JSC::jsString):
(JSC::jsAdd):
(JSC::resolveBase):

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1/*
2 * Copyright (C) 1999-2002 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24#include "JSString.h"
25
26#include "JSGlobalObject.h"
27#include "JSObject.h"
28#include "Operations.h"
29#include "StringObject.h"
30#include "StringPrototype.h"
31
32namespace JSC {
33
34void JSString::Rope::destructNonRecursive()
35{
36 Vector<Rope*, 32> workQueue;
37 Rope* rope = this;
38
39 while (true) {
40 unsigned length = rope->ropeLength();
41 for (unsigned i = 0; i < length; ++i) {
42 Fiber& fiber = rope->fibers(i);
43 if (fiber.isString())
44 fiber.string()->deref();
45 else {
46 Rope* nextRope = fiber.rope();
47 if (nextRope->hasOneRef())
48 workQueue.append(nextRope);
49 else
50 nextRope->deref();
51 }
52 }
53 if (rope != this)
54 fastFree(rope);
55
56 if (workQueue.isEmpty())
57 return;
58
59 rope = workQueue.last();
60 workQueue.removeLast();
61 }
62}
63
64JSString::Rope::~Rope()
65{
66 destructNonRecursive();
67}
68
69#define ROPE_COPY_CHARS_INLINE_CUTOFF 20
70
71static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
72{
73#ifdef ROPE_COPY_CHARS_INLINE_CUTOFF
74 if (numCharacters <= ROPE_COPY_CHARS_INLINE_CUTOFF) {
75 for (unsigned i = 0; i < numCharacters; ++i)
76 destination[i] = source[i];
77 return;
78 }
79#endif
80 memcpy(destination, source, numCharacters * sizeof(UChar));
81}
82
83// Overview: this methods converts a JSString from holding a string in rope form
84// down to a simple UString representation. It does so by building up the string
85// backwards, since we want to avoid recursion, we expect that the tree structure
86// representing the rope is likely imbalanced with more nodes down the left side
87// (since appending to the string is likely more common) - and as such resolving
88// in this fashion should minimize work queue size. (If we built the queue forwards
89// we would likely have to place all of the constituent UString::Reps into the
90// Vector before performing any concatenation, but by working backwards we likely
91// only fill the queue with the number of substrings at any given level in a
92// rope-of-ropes.)
93void JSString::resolveRope(ExecState* exec) const
94{
95 ASSERT(isRope());
96
97 // Allocate the buffer to hold the final string, position initially points to the end.
98 UChar* buffer;
99 if (!tryFastMalloc(m_stringLength * sizeof(UChar)).getValue(buffer)) {
100 for (unsigned i = 0; i < m_ropeLength; ++i)
101 m_fibers[i].deref();
102 m_ropeLength = 0;
103 ASSERT(!isRope());
104 ASSERT(m_value == UString());
105
106 throwOutOfMemoryError(exec);
107 return;
108 }
109 UChar* position = buffer + m_stringLength;
110
111 // Start with the current Rope.
112 Vector<Rope::Fiber, 32> workQueue;
113 Rope::Fiber currentFiber;
114 for (unsigned i = 0; i < (m_ropeLength - 1); ++i)
115 workQueue.append(m_fibers[i]);
116 currentFiber = m_fibers[m_ropeLength - 1];
117 while (true) {
118 if (currentFiber.isRope()) {
119 Rope* rope = currentFiber.rope();
120 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
121 // (we will be working backwards over the rope).
122 unsigned ropeLengthMinusOne = rope->ropeLength() - 1;
123 for (unsigned i = 0; i < ropeLengthMinusOne; ++i)
124 workQueue.append(rope->fibers(i));
125 currentFiber = rope->fibers(ropeLengthMinusOne);
126 } else {
127 UString::Rep* string = currentFiber.string();
128 unsigned length = string->len;
129 position -= length;
130 copyChars(position, string->data(), length);
131
132 // Was this the last item in the work queue?
133 if (workQueue.isEmpty()) {
134 // Create a string from the UChar buffer, clear the rope RefPtr.
135 ASSERT(buffer == position);
136 m_value = UString::Rep::create(buffer, m_stringLength);
137 for (unsigned i = 0; i < m_ropeLength; ++i)
138 m_fibers[i].deref();
139 m_ropeLength = 0;
140
141 ASSERT(!isRope());
142 return;
143 }
144
145 // No! - set the next item up to process.
146 currentFiber = workQueue.last();
147 workQueue.removeLast();
148 }
149 }
150}
151
152JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
153{
154 return const_cast<JSString*>(this);
155}
156
157bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
158{
159 result = this;
160 number = value(exec).toDouble();
161 return false;
162}
163
164bool JSString::toBoolean(ExecState*) const
165{
166 return m_stringLength;
167}
168
169double JSString::toNumber(ExecState* exec) const
170{
171 return value(exec).toDouble();
172}
173
174UString JSString::toString(ExecState* exec) const
175{
176 return value(exec);
177}
178
179UString JSString::toThisString(ExecState* exec) const
180{
181 return value(exec);
182}
183
184JSString* JSString::toThisJSString(ExecState*)
185{
186 return this;
187}
188
189inline StringObject* StringObject::create(ExecState* exec, JSString* string)
190{
191 return new (exec) StringObject(exec->lexicalGlobalObject()->stringObjectStructure(), string);
192}
193
194JSObject* JSString::toObject(ExecState* exec) const
195{
196 return StringObject::create(exec, const_cast<JSString*>(this));
197}
198
199JSObject* JSString::toThisObject(ExecState* exec) const
200{
201 return StringObject::create(exec, const_cast<JSString*>(this));
202}
203
204bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
205{
206 // The semantics here are really getPropertySlot, not getOwnPropertySlot.
207 // This function should only be called by JSValue::get.
208 if (getStringPropertySlot(exec, propertyName, slot))
209 return true;
210 if (propertyName == exec->propertyNames().underscoreProto) {
211 slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
212 return true;
213 }
214 slot.setBase(this);
215 JSObject* object;
216 for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) {
217 object = asObject(prototype);
218 if (object->getOwnPropertySlot(exec, propertyName, slot))
219 return true;
220 }
221 slot.setUndefined();
222 return true;
223}
224
225bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
226{
227 if (propertyName == exec->propertyNames().length) {
228 descriptor.setDescriptor(jsNumber(exec, m_stringLength), DontEnum | DontDelete | ReadOnly);
229 return true;
230 }
231
232 bool isStrictUInt32;
233 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
234 if (isStrictUInt32 && i < m_stringLength) {
235 descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly);
236 return true;
237 }
238
239 return false;
240}
241
242bool JSString::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
243{
244 if (getStringPropertyDescriptor(exec, propertyName, descriptor))
245 return true;
246 if (propertyName != exec->propertyNames().underscoreProto)
247 return false;
248 descriptor.setDescriptor(exec->lexicalGlobalObject()->stringPrototype(), DontEnum);
249 return true;
250}
251
252bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
253{
254 // The semantics here are really getPropertySlot, not getOwnPropertySlot.
255 // This function should only be called by JSValue::get.
256 if (getStringPropertySlot(exec, propertyName, slot))
257 return true;
258 return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
259}
260
261} // namespace JSC
Note: See TracBrowser for help on using the repository browser.