]>
git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSString.cpp
2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
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.
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.
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.
26 #include "JSGlobalObject.h"
28 #include "Operations.h"
29 #include "StringObject.h"
30 #include "StringPrototype.h"
34 void JSString::Rope::destructNonRecursive()
36 Vector
<Rope
*, 32> workQueue
;
40 unsigned length
= rope
->ropeLength();
41 for (unsigned i
= 0; i
< length
; ++i
) {
42 Fiber
& fiber
= rope
->fibers(i
);
44 fiber
.string()->deref();
46 Rope
* nextRope
= fiber
.rope();
47 if (nextRope
->hasOneRef())
48 workQueue
.append(nextRope
);
56 if (workQueue
.isEmpty())
59 rope
= workQueue
.last();
60 workQueue
.removeLast();
64 JSString::Rope::~Rope()
66 destructNonRecursive();
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
79 void JSString::resolveRope(ExecState
* exec
) const
83 // Allocate the buffer to hold the final string, position initially points to the end.
85 if (PassRefPtr
<UStringImpl
> newImpl
= UStringImpl::tryCreateUninitialized(m_stringLength
, buffer
))
88 for (unsigned i
= 0; i
< m_ropeLength
; ++i
) {
90 m_fibers
[i
] = static_cast<void*>(0);
94 ASSERT(m_value
== UString());
95 throwOutOfMemoryError(exec
);
98 UChar
* position
= buffer
+ m_stringLength
;
100 // Start with the current Rope.
101 Vector
<Rope::Fiber
, 32> workQueue
;
102 Rope::Fiber currentFiber
;
103 for (unsigned i
= 0; i
< (m_ropeLength
- 1); ++i
)
104 workQueue
.append(m_fibers
[i
]);
105 currentFiber
= m_fibers
[m_ropeLength
- 1];
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 ropeLengthMinusOne
= rope
->ropeLength() - 1;
112 for (unsigned i
= 0; i
< ropeLengthMinusOne
; ++i
)
113 workQueue
.append(rope
->fibers(i
));
114 currentFiber
= rope
->fibers(ropeLengthMinusOne
);
116 UString::Rep
* string
= currentFiber
.string();
117 unsigned length
= string
->size();
119 UStringImpl::copyChars(position
, string
->data(), length
);
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_ropeLength
; ++i
) {
127 m_fibers
[i
] = static_cast<void*>(0);
135 // No! - set the next item up to process.
136 currentFiber
= workQueue
.last();
137 workQueue
.removeLast();
142 JSValue
JSString::toPrimitive(ExecState
*, PreferredPrimitiveType
) const
144 return const_cast<JSString
*>(this);
147 bool JSString::getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
& result
)
150 number
= value(exec
).toDouble();
154 bool JSString::toBoolean(ExecState
*) const
156 return m_stringLength
;
159 double JSString::toNumber(ExecState
* exec
) const
161 return value(exec
).toDouble();
164 UString
JSString::toString(ExecState
* exec
) const
169 UString
JSString::toThisString(ExecState
* exec
) const
174 JSString
* JSString::toThisJSString(ExecState
*)
179 inline StringObject
* StringObject::create(ExecState
* exec
, JSString
* string
)
181 return new (exec
) StringObject(exec
->lexicalGlobalObject()->stringObjectStructure(), string
);
184 JSObject
* JSString::toObject(ExecState
* exec
) const
186 return StringObject::create(exec
, const_cast<JSString
*>(this));
189 JSObject
* JSString::toThisObject(ExecState
* exec
) const
191 return StringObject::create(exec
, const_cast<JSString
*>(this));
194 bool JSString::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
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
))
200 if (propertyName
== exec
->propertyNames().underscoreProto
) {
201 slot
.setValue(exec
->lexicalGlobalObject()->stringPrototype());
206 for (JSValue prototype
= exec
->lexicalGlobalObject()->stringPrototype(); !prototype
.isNull(); prototype
= object
->prototype()) {
207 object
= asObject(prototype
);
208 if (object
->getOwnPropertySlot(exec
, propertyName
, slot
))
215 bool JSString::getStringPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
217 if (propertyName
== exec
->propertyNames().length
) {
218 descriptor
.setDescriptor(jsNumber(exec
, m_stringLength
), DontEnum
| DontDelete
| ReadOnly
);
223 unsigned i
= propertyName
.toStrictUInt32(&isStrictUInt32
);
224 if (isStrictUInt32
&& i
< m_stringLength
) {
225 descriptor
.setDescriptor(jsSingleCharacterSubstring(exec
, value(exec
), i
), DontDelete
| ReadOnly
);
232 bool JSString::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
234 if (getStringPropertyDescriptor(exec
, propertyName
, descriptor
))
236 if (propertyName
!= exec
->propertyNames().underscoreProto
)
238 descriptor
.setDescriptor(exec
->lexicalGlobalObject()->stringPrototype(), DontEnum
);
242 bool JSString::getOwnPropertySlot(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
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
))
248 return JSString::getOwnPropertySlot(exec
, Identifier::from(exec
, propertyName
), slot
);