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

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

Some general Rope related refactoring.

Reviewed by Oliver Hunt.

Rename Rope::m_ropeLength to m_fiberCount, to be more descriptive.
Rename Rope::m_stringLength to simply m_length (since this is the
more conventional name for the length of a string). Move append
behaviour out into a new RopeBuilder class, so that Rope no longer
needs any knowledge of the JSString or UString implementation.

Make Rope no longer be nested within JSString.
(Rope now no-longer need reside within JSString.h, but leaving
the change of moving this out to a different header as a separate
change from these renames).

(JSC::JIT::privateCompileCTIMachineTrampolines):

  • runtime/JSString.cpp:

(JSC::Rope::destructNonRecursive):
(JSC::Rope::~Rope):
(JSC::JSString::resolveRope):
(JSC::JSString::toBoolean):
(JSC::JSString::getStringPropertyDescriptor):

  • runtime/JSString.h:

(JSC::Rope::Fiber::Fiber):
(JSC::Rope::Fiber::deref):
(JSC::Rope::Fiber::ref):
(JSC::Rope::Fiber::refAndGetLength):
(JSC::Rope::Fiber::isRope):
(JSC::Rope::Fiber::rope):
(JSC::Rope::Fiber::isString):
(JSC::Rope::Fiber::string):
(JSC::Rope::Fiber::nonFiber):
(JSC::Rope::tryCreateUninitialized):
(JSC::Rope::append):
(JSC::Rope::fiberCount):
(JSC::Rope::length):
(JSC::Rope::fibers):
(JSC::Rope::Rope):
(JSC::Rope::operator new):
(JSC::):
(JSC::RopeBuilder::JSString):
(JSC::RopeBuilder::~JSString):
(JSC::RopeBuilder::length):
(JSC::RopeBuilder::canGetIndex):
(JSC::RopeBuilder::appendStringInConstruct):
(JSC::RopeBuilder::appendValueInConstructAndIncrementLength):
(JSC::RopeBuilder::isRope):
(JSC::RopeBuilder::fiberCount):
(JSC::JSString::getStringPropertySlot):

  • runtime/Operations.h:

(JSC::jsString):

  • Property svn:eol-style set to native
File size: 8.2 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 Rope::destructNonRecursive()
35{
36 Vector<Rope*, 32> workQueue;
37 Rope* rope = this;
38
39 while (true) {
40 unsigned length = rope->fiberCount();
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
64Rope::~Rope()
65{
66 destructNonRecursive();
67}
68
69// Overview: this methods converts a JSString from holding a string in rope form
70// down to a simple UString representation. It does so by building up the string
71// backwards, since we want to avoid recursion, we expect that the tree structure
72// representing the rope is likely imbalanced with more nodes down the left side
73// (since appending to the string is likely more common) - and as such resolving
74// in this fashion should minimize work queue size. (If we built the queue forwards
75// we would likely have to place all of the constituent UString::Reps into the
76// Vector before performing any concatenation, but by working backwards we likely
77// only fill the queue with the number of substrings at any given level in a
78// rope-of-ropes.)
79void JSString::resolveRope(ExecState* exec) const
80{
81 ASSERT(isRope());
82
83 // Allocate the buffer to hold the final string, position initially points to the end.
84 UChar* buffer;
85 if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_length, buffer))
86 m_value = newImpl;
87 else {
88 for (unsigned i = 0; i < m_fiberCount; ++i) {
89 m_fibers[i].deref();
90 m_fibers[i] = static_cast<void*>(0);
91 }
92 m_fiberCount = 0;
93 ASSERT(!isRope());
94 ASSERT(m_value == UString());
95 throwOutOfMemoryError(exec);
96 return;
97 }
98 UChar* position = buffer + m_length;
99
100 // Start with the current Rope.
101 Vector<Rope::Fiber, 32> workQueue;
102 Rope::Fiber currentFiber;
103 for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
104 workQueue.append(m_fibers[i]);
105 currentFiber = m_fibers[m_fiberCount - 1];
106 while (true) {
107 if (currentFiber.isRope()) {
108 Rope* rope = currentFiber.rope();
109 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
110 // (we will be working backwards over the rope).
111 unsigned fiberCountMinusOne = rope->fiberCount() - 1;
112 for (unsigned i = 0; i < fiberCountMinusOne; ++i)
113 workQueue.append(rope->fibers(i));
114 currentFiber = rope->fibers(fiberCountMinusOne);
115 } else {
116 UString::Rep* string = currentFiber.string();
117 unsigned length = string->size();
118 position -= length;
119 UStringImpl::copyChars(position, string->data(), length);
120
121 // Was this the last item in the work queue?
122 if (workQueue.isEmpty()) {
123 // Create a string from the UChar buffer, clear the rope RefPtr.
124 ASSERT(buffer == position);
125 for (unsigned i = 0; i < m_fiberCount; ++i) {
126 m_fibers[i].deref();
127 m_fibers[i] = static_cast<void*>(0);
128 }
129 m_fiberCount = 0;
130
131 ASSERT(!isRope());
132 return;
133 }
134
135 // No! - set the next item up to process.
136 currentFiber = workQueue.last();
137 workQueue.removeLast();
138 }
139 }
140}
141
142JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
143{
144 return const_cast<JSString*>(this);
145}
146
147bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
148{
149 result = this;
150 number = value(exec).toDouble();
151 return false;
152}
153
154bool JSString::toBoolean(ExecState*) const
155{
156 return m_length;
157}
158
159double JSString::toNumber(ExecState* exec) const
160{
161 return value(exec).toDouble();
162}
163
164UString JSString::toString(ExecState* exec) const
165{
166 return value(exec);
167}
168
169UString JSString::toThisString(ExecState* exec) const
170{
171 return value(exec);
172}
173
174JSString* JSString::toThisJSString(ExecState*)
175{
176 return this;
177}
178
179inline StringObject* StringObject::create(ExecState* exec, JSString* string)
180{
181 return new (exec) StringObject(exec->lexicalGlobalObject()->stringObjectStructure(), string);
182}
183
184JSObject* JSString::toObject(ExecState* exec) const
185{
186 return StringObject::create(exec, const_cast<JSString*>(this));
187}
188
189JSObject* JSString::toThisObject(ExecState* exec) const
190{
191 return StringObject::create(exec, const_cast<JSString*>(this));
192}
193
194bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
195{
196 // The semantics here are really getPropertySlot, not getOwnPropertySlot.
197 // This function should only be called by JSValue::get.
198 if (getStringPropertySlot(exec, propertyName, slot))
199 return true;
200 if (propertyName == exec->propertyNames().underscoreProto) {
201 slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
202 return true;
203 }
204 slot.setBase(this);
205 JSObject* object;
206 for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) {
207 object = asObject(prototype);
208 if (object->getOwnPropertySlot(exec, propertyName, slot))
209 return true;
210 }
211 slot.setUndefined();
212 return true;
213}
214
215bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
216{
217 if (propertyName == exec->propertyNames().length) {
218 descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly);
219 return true;
220 }
221
222 bool isStrictUInt32;
223 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
224 if (isStrictUInt32 && i < m_length) {
225 descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly);
226 return true;
227 }
228
229 return false;
230}
231
232bool JSString::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
233{
234 if (getStringPropertyDescriptor(exec, propertyName, descriptor))
235 return true;
236 if (propertyName != exec->propertyNames().underscoreProto)
237 return false;
238 descriptor.setDescriptor(exec->lexicalGlobalObject()->stringPrototype(), DontEnum);
239 return true;
240}
241
242bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
243{
244 // The semantics here are really getPropertySlot, not getOwnPropertySlot.
245 // This function should only be called by JSValue::get.
246 if (getStringPropertySlot(exec, propertyName, slot))
247 return true;
248 return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
249}
250
251} // namespace JSC
Note: See TracBrowser for help on using the repository browser.