]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
4 | * Copyright (C) 2003, 2004, 2005, 2006, 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 | #ifndef JSString_h | |
24 | #define JSString_h | |
25 | ||
9dae56ea | 26 | #include "CallFrame.h" |
ba379fdc | 27 | #include "CommonIdentifiers.h" |
9dae56ea | 28 | #include "Identifier.h" |
f9bf01c6 | 29 | #include "PropertyDescriptor.h" |
9dae56ea | 30 | #include "PropertySlot.h" |
4e4e5a6f | 31 | #include "RopeImpl.h" |
14957cd0 | 32 | #include "Structure.h" |
9dae56ea A |
33 | |
34 | namespace JSC { | |
35 | ||
36 | class JSString; | |
37 | ||
38 | JSString* jsEmptyString(JSGlobalData*); | |
39 | JSString* jsEmptyString(ExecState*); | |
40 | JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string | |
41 | JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string | |
42 | ||
43 | JSString* jsSingleCharacterString(JSGlobalData*, UChar); | |
44 | JSString* jsSingleCharacterString(ExecState*, UChar); | |
9dae56ea A |
45 | JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset); |
46 | JSString* jsSubstring(JSGlobalData*, const UString&, unsigned offset, unsigned length); | |
47 | JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length); | |
48 | ||
49 | // Non-trivial strings are two or more characters long. | |
50 | // These functions are faster than just calling jsString. | |
51 | JSString* jsNontrivialString(JSGlobalData*, const UString&); | |
52 | JSString* jsNontrivialString(ExecState*, const UString&); | |
53 | JSString* jsNontrivialString(JSGlobalData*, const char*); | |
54 | JSString* jsNontrivialString(ExecState*, const char*); | |
55 | ||
56 | // Should be used for strings that are owned by an object that will | |
57 | // likely outlive the JSValue this makes, such as the parse tree or a | |
58 | // DOM object that contains a UString | |
59 | JSString* jsOwnedString(JSGlobalData*, const UString&); | |
60 | JSString* jsOwnedString(ExecState*, const UString&); | |
61 | ||
f9bf01c6 | 62 | class JS_EXPORTCLASS JSString : public JSCell { |
9dae56ea | 63 | public: |
f9bf01c6 A |
64 | friend class JIT; |
65 | friend class JSGlobalData; | |
4e4e5a6f A |
66 | friend class SpecializedThunkJIT; |
67 | friend struct ThunkHelpers; | |
f9bf01c6 | 68 | |
4e4e5a6f | 69 | class RopeBuilder { |
f9bf01c6 | 70 | public: |
4e4e5a6f A |
71 | RopeBuilder(unsigned fiberCount) |
72 | : m_index(0) | |
73 | , m_rope(RopeImpl::tryCreateUninitialized(fiberCount)) | |
74 | { | |
75 | } | |
76 | ||
77 | bool isOutOfMemory() { return !m_rope; } | |
78 | ||
79 | void append(RopeImpl::Fiber& fiber) | |
80 | { | |
81 | ASSERT(m_rope); | |
82 | m_rope->initializeFiber(m_index, fiber); | |
83 | } | |
84 | void append(const UString& string) | |
85 | { | |
86 | ASSERT(m_rope); | |
14957cd0 | 87 | m_rope->initializeFiber(m_index, string.impl()); |
4e4e5a6f A |
88 | } |
89 | void append(JSString* jsString) | |
90 | { | |
91 | if (jsString->isRope()) { | |
92 | for (unsigned i = 0; i < jsString->m_fiberCount; ++i) | |
14957cd0 | 93 | append(jsString->m_fibers[i]); |
4e4e5a6f A |
94 | } else |
95 | append(jsString->string()); | |
96 | } | |
97 | ||
98 | PassRefPtr<RopeImpl> release() | |
99 | { | |
100 | ASSERT(m_index == m_rope->fiberCount()); | |
101 | return m_rope.release(); | |
102 | } | |
f9bf01c6 | 103 | |
4e4e5a6f | 104 | unsigned length() { return m_rope->length(); } |
f9bf01c6 | 105 | |
4e4e5a6f A |
106 | private: |
107 | unsigned m_index; | |
108 | RefPtr<RopeImpl> m_rope; | |
109 | }; | |
110 | ||
111 | class RopeIterator { | |
112 | public: | |
113 | RopeIterator() { } | |
114 | ||
115 | RopeIterator(RopeImpl::Fiber* fibers, size_t fiberCount) | |
f9bf01c6 | 116 | { |
4e4e5a6f A |
117 | ASSERT(fiberCount); |
118 | m_workQueue.append(WorkItem(fibers, fiberCount)); | |
119 | skipRopes(); | |
f9bf01c6 A |
120 | } |
121 | ||
4e4e5a6f | 122 | RopeIterator& operator++() |
f9bf01c6 | 123 | { |
4e4e5a6f A |
124 | WorkItem& item = m_workQueue.last(); |
125 | ASSERT(!RopeImpl::isRope(item.fibers[item.i])); | |
126 | if (++item.i == item.fiberCount) | |
127 | m_workQueue.removeLast(); | |
128 | skipRopes(); | |
f9bf01c6 A |
129 | return *this; |
130 | } | |
131 | ||
14957cd0 | 132 | StringImpl* operator*() |
f9bf01c6 | 133 | { |
4e4e5a6f A |
134 | WorkItem& item = m_workQueue.last(); |
135 | RopeImpl::Fiber fiber = item.fibers[item.i]; | |
136 | ASSERT(!RopeImpl::isRope(fiber)); | |
14957cd0 | 137 | return static_cast<StringImpl*>(fiber); |
f9bf01c6 A |
138 | } |
139 | ||
4e4e5a6f A |
140 | bool operator!=(const RopeIterator& other) const |
141 | { | |
142 | return m_workQueue != other.m_workQueue; | |
143 | } | |
f9bf01c6 | 144 | |
f9bf01c6 | 145 | private: |
4e4e5a6f A |
146 | struct WorkItem { |
147 | WorkItem(RopeImpl::Fiber* fibers, size_t fiberCount) | |
148 | : fibers(fibers) | |
149 | , fiberCount(fiberCount) | |
150 | , i(0) | |
151 | { | |
152 | } | |
f9bf01c6 | 153 | |
4e4e5a6f A |
154 | bool operator!=(const WorkItem& other) const |
155 | { | |
156 | return fibers != other.fibers || fiberCount != other.fiberCount || i != other.i; | |
157 | } | |
f9bf01c6 | 158 | |
4e4e5a6f A |
159 | RopeImpl::Fiber* fibers; |
160 | size_t fiberCount; | |
161 | size_t i; | |
162 | }; | |
f9bf01c6 | 163 | |
4e4e5a6f A |
164 | void skipRopes() |
165 | { | |
166 | if (m_workQueue.isEmpty()) | |
167 | return; | |
168 | ||
169 | while (1) { | |
170 | WorkItem& item = m_workQueue.last(); | |
171 | RopeImpl::Fiber fiber = item.fibers[item.i]; | |
172 | if (!RopeImpl::isRope(fiber)) | |
173 | break; | |
174 | RopeImpl* rope = static_cast<RopeImpl*>(fiber); | |
175 | if (++item.i == item.fiberCount) | |
176 | m_workQueue.removeLast(); | |
177 | m_workQueue.append(WorkItem(rope->fibers(), rope->fiberCount())); | |
178 | } | |
179 | } | |
f9bf01c6 | 180 | |
4e4e5a6f | 181 | Vector<WorkItem, 16> m_workQueue; |
f9bf01c6 A |
182 | }; |
183 | ||
184 | ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value) | |
14957cd0 A |
185 | : JSCell(*globalData, globalData->stringStructure.get()) |
186 | , m_length(value.length()) | |
9dae56ea | 187 | , m_value(value) |
4e4e5a6f | 188 | , m_fiberCount(0) |
9dae56ea | 189 | { |
4e4e5a6f | 190 | ASSERT(!m_value.isNull()); |
14957cd0 | 191 | Heap::heap(this)->reportExtraMemoryCost(value.impl()->cost()); |
9dae56ea A |
192 | } |
193 | ||
194 | enum HasOtherOwnerType { HasOtherOwner }; | |
195 | JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) | |
14957cd0 A |
196 | : JSCell(*globalData, globalData->stringStructure.get()) |
197 | , m_length(value.length()) | |
9dae56ea | 198 | , m_value(value) |
4e4e5a6f | 199 | , m_fiberCount(0) |
9dae56ea | 200 | { |
4e4e5a6f | 201 | ASSERT(!m_value.isNull()); |
9dae56ea | 202 | } |
14957cd0 A |
203 | JSString(JSGlobalData* globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType) |
204 | : JSCell(*globalData, globalData->stringStructure.get()) | |
4e4e5a6f | 205 | , m_length(value->length()) |
9dae56ea | 206 | , m_value(value) |
4e4e5a6f | 207 | , m_fiberCount(0) |
9dae56ea | 208 | { |
4e4e5a6f | 209 | ASSERT(!m_value.isNull()); |
9dae56ea | 210 | } |
4e4e5a6f | 211 | JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope) |
14957cd0 | 212 | : JSCell(*globalData, globalData->stringStructure.get()) |
4e4e5a6f A |
213 | , m_length(rope->length()) |
214 | , m_fiberCount(1) | |
f9bf01c6 | 215 | { |
14957cd0 | 216 | m_fibers[0] = rope.leakRef(); |
f9bf01c6 A |
217 | } |
218 | // This constructor constructs a new string by concatenating s1 & s2. | |
4e4e5a6f A |
219 | // This should only be called with fiberCount <= 3. |
220 | JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, JSString* s2) | |
14957cd0 | 221 | : JSCell(*globalData, globalData->stringStructure.get()) |
4e4e5a6f A |
222 | , m_length(s1->length() + s2->length()) |
223 | , m_fiberCount(fiberCount) | |
f9bf01c6 | 224 | { |
4e4e5a6f | 225 | ASSERT(fiberCount <= s_maxInternalRopeLength); |
f9bf01c6 A |
226 | unsigned index = 0; |
227 | appendStringInConstruct(index, s1); | |
228 | appendStringInConstruct(index, s2); | |
4e4e5a6f | 229 | ASSERT(fiberCount == index); |
f9bf01c6 A |
230 | } |
231 | // This constructor constructs a new string by concatenating s1 & s2. | |
4e4e5a6f A |
232 | // This should only be called with fiberCount <= 3. |
233 | JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, const UString& u2) | |
14957cd0 A |
234 | : JSCell(*globalData, globalData->stringStructure.get()) |
235 | , m_length(s1->length() + u2.length()) | |
4e4e5a6f | 236 | , m_fiberCount(fiberCount) |
f9bf01c6 | 237 | { |
4e4e5a6f | 238 | ASSERT(fiberCount <= s_maxInternalRopeLength); |
f9bf01c6 A |
239 | unsigned index = 0; |
240 | appendStringInConstruct(index, s1); | |
241 | appendStringInConstruct(index, u2); | |
4e4e5a6f | 242 | ASSERT(fiberCount == index); |
f9bf01c6 A |
243 | } |
244 | // This constructor constructs a new string by concatenating s1 & s2. | |
4e4e5a6f A |
245 | // This should only be called with fiberCount <= 3. |
246 | JSString(JSGlobalData* globalData, unsigned fiberCount, const UString& u1, JSString* s2) | |
14957cd0 A |
247 | : JSCell(*globalData, globalData->stringStructure.get()) |
248 | , m_length(u1.length() + s2->length()) | |
4e4e5a6f | 249 | , m_fiberCount(fiberCount) |
f9bf01c6 | 250 | { |
4e4e5a6f | 251 | ASSERT(fiberCount <= s_maxInternalRopeLength); |
f9bf01c6 A |
252 | unsigned index = 0; |
253 | appendStringInConstruct(index, u1); | |
254 | appendStringInConstruct(index, s2); | |
4e4e5a6f | 255 | ASSERT(fiberCount == index); |
f9bf01c6 A |
256 | } |
257 | // This constructor constructs a new string by concatenating v1, v2 & v3. | |
4e4e5a6f A |
258 | // This should only be called with fiberCount <= 3 ... which since every |
259 | // value must require a fiberCount of at least one implies that the length | |
f9bf01c6 A |
260 | // for each value must be exactly 1! |
261 | JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) | |
14957cd0 | 262 | : JSCell(exec->globalData(), exec->globalData().stringStructure.get()) |
4e4e5a6f A |
263 | , m_length(0) |
264 | , m_fiberCount(s_maxInternalRopeLength) | |
f9bf01c6 A |
265 | { |
266 | unsigned index = 0; | |
267 | appendValueInConstructAndIncrementLength(exec, index, v1); | |
268 | appendValueInConstructAndIncrementLength(exec, index, v2); | |
269 | appendValueInConstructAndIncrementLength(exec, index, v3); | |
270 | ASSERT(index == s_maxInternalRopeLength); | |
271 | } | |
272 | ||
4e4e5a6f A |
273 | // This constructor constructs a new string by concatenating u1 & u2. |
274 | JSString(JSGlobalData* globalData, const UString& u1, const UString& u2) | |
14957cd0 A |
275 | : JSCell(*globalData, globalData->stringStructure.get()) |
276 | , m_length(u1.length() + u2.length()) | |
4e4e5a6f A |
277 | , m_fiberCount(2) |
278 | { | |
279 | unsigned index = 0; | |
280 | appendStringInConstruct(index, u1); | |
281 | appendStringInConstruct(index, u2); | |
282 | ASSERT(index <= s_maxInternalRopeLength); | |
283 | } | |
284 | ||
285 | // This constructor constructs a new string by concatenating u1, u2 & u3. | |
286 | JSString(JSGlobalData* globalData, const UString& u1, const UString& u2, const UString& u3) | |
14957cd0 A |
287 | : JSCell(*globalData, globalData->stringStructure.get()) |
288 | , m_length(u1.length() + u2.length() + u3.length()) | |
4e4e5a6f A |
289 | , m_fiberCount(s_maxInternalRopeLength) |
290 | { | |
291 | unsigned index = 0; | |
292 | appendStringInConstruct(index, u1); | |
293 | appendStringInConstruct(index, u2); | |
294 | appendStringInConstruct(index, u3); | |
295 | ASSERT(index <= s_maxInternalRopeLength); | |
296 | } | |
297 | ||
f9bf01c6 A |
298 | ~JSString() |
299 | { | |
300 | ASSERT(vptr() == JSGlobalData::jsStringVPtr); | |
4e4e5a6f | 301 | for (unsigned i = 0; i < m_fiberCount; ++i) |
14957cd0 | 302 | RopeImpl::deref(m_fibers[i]); |
f9bf01c6 A |
303 | } |
304 | ||
305 | const UString& value(ExecState* exec) const | |
306 | { | |
307 | if (isRope()) | |
308 | resolveRope(exec); | |
309 | return m_value; | |
310 | } | |
4e4e5a6f | 311 | const UString& tryGetValue() const |
f9bf01c6 A |
312 | { |
313 | if (isRope()) | |
4e4e5a6f | 314 | resolveRope(0); |
f9bf01c6 A |
315 | return m_value; |
316 | } | |
4e4e5a6f | 317 | unsigned length() { return m_length; } |
9dae56ea A |
318 | |
319 | bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | |
320 | bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); | |
f9bf01c6 | 321 | bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); |
9dae56ea | 322 | |
4e4e5a6f | 323 | bool canGetIndex(unsigned i) { return i < m_length; } |
f9bf01c6 | 324 | JSString* getIndex(ExecState*, unsigned); |
4e4e5a6f A |
325 | JSString* getIndexSlowCase(ExecState*, unsigned); |
326 | ||
327 | JSValue replaceCharacter(ExecState*, UChar, const UString& replacement); | |
9dae56ea | 328 | |
14957cd0 A |
329 | static Structure* createStructure(JSGlobalData& globalData, JSValue proto) |
330 | { | |
331 | return Structure::create(globalData, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount, &s_info); | |
332 | } | |
333 | ||
334 | static const ClassInfo s_info; | |
9dae56ea A |
335 | |
336 | private: | |
9dae56ea | 337 | JSString(VPtrStealingHackType) |
14957cd0 | 338 | : JSCell(VPtrStealingHack) |
4e4e5a6f | 339 | , m_fiberCount(0) |
f9bf01c6 A |
340 | { |
341 | } | |
342 | ||
343 | void resolveRope(ExecState*) const; | |
14957cd0 A |
344 | void resolveRopeSlowCase(ExecState*, UChar*) const; |
345 | void outOfMemory(ExecState*) const; | |
b80e6193 | 346 | JSString* substringFromRope(ExecState*, unsigned offset, unsigned length); |
f9bf01c6 A |
347 | |
348 | void appendStringInConstruct(unsigned& index, const UString& string) | |
349 | { | |
14957cd0 | 350 | StringImpl* impl = string.impl(); |
4e4e5a6f | 351 | impl->ref(); |
14957cd0 | 352 | m_fibers[index++] = impl; |
f9bf01c6 A |
353 | } |
354 | ||
355 | void appendStringInConstruct(unsigned& index, JSString* jsString) | |
356 | { | |
357 | if (jsString->isRope()) { | |
4e4e5a6f | 358 | for (unsigned i = 0; i < jsString->m_fiberCount; ++i) { |
14957cd0 | 359 | RopeImpl::Fiber fiber = jsString->m_fibers[i]; |
4e4e5a6f | 360 | fiber->ref(); |
14957cd0 | 361 | m_fibers[index++] = fiber; |
4e4e5a6f | 362 | } |
f9bf01c6 A |
363 | } else |
364 | appendStringInConstruct(index, jsString->string()); | |
365 | } | |
366 | ||
367 | void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v) | |
9dae56ea | 368 | { |
f9bf01c6 | 369 | if (v.isString()) { |
14957cd0 A |
370 | ASSERT(v.asCell()->isString()); |
371 | JSString* s = static_cast<JSString*>(v.asCell()); | |
372 | ASSERT(s->fiberCount() == 1); | |
f9bf01c6 | 373 | appendStringInConstruct(index, s); |
4e4e5a6f | 374 | m_length += s->length(); |
f9bf01c6 A |
375 | } else { |
376 | UString u(v.toString(exec)); | |
14957cd0 | 377 | StringImpl* impl = u.impl(); |
4e4e5a6f | 378 | impl->ref(); |
14957cd0 A |
379 | m_fibers[index++] = impl; |
380 | m_length += u.length(); | |
f9bf01c6 | 381 | } |
9dae56ea A |
382 | } |
383 | ||
ba379fdc A |
384 | virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; |
385 | virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); | |
9dae56ea A |
386 | virtual bool toBoolean(ExecState*) const; |
387 | virtual double toNumber(ExecState*) const; | |
14957cd0 | 388 | virtual JSObject* toObject(ExecState*, JSGlobalObject*) const; |
9dae56ea A |
389 | virtual UString toString(ExecState*) const; |
390 | ||
391 | virtual JSObject* toThisObject(ExecState*) const; | |
9dae56ea A |
392 | |
393 | // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). | |
394 | virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | |
395 | virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); | |
f9bf01c6 A |
396 | virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); |
397 | ||
398 | static const unsigned s_maxInternalRopeLength = 3; | |
399 | ||
4e4e5a6f A |
400 | // A string is represented either by a UString or a RopeImpl. |
401 | unsigned m_length; | |
f9bf01c6 | 402 | mutable UString m_value; |
4e4e5a6f | 403 | mutable unsigned m_fiberCount; |
14957cd0 | 404 | mutable FixedArray<RopeImpl::Fiber, s_maxInternalRopeLength> m_fibers; |
f9bf01c6 | 405 | |
4e4e5a6f | 406 | bool isRope() const { return m_fiberCount; } |
f9bf01c6 | 407 | UString& string() { ASSERT(!isRope()); return m_value; } |
14957cd0 | 408 | unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; } |
f9bf01c6 A |
409 | |
410 | friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); | |
411 | friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2); | |
412 | friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2); | |
413 | friend JSValue jsString(ExecState* exec, Register* strings, unsigned count); | |
14957cd0 | 414 | friend JSValue jsString(ExecState* exec, JSValue thisValue); |
b80e6193 | 415 | friend JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length); |
9dae56ea A |
416 | }; |
417 | ||
ba379fdc | 418 | JSString* asString(JSValue); |
9dae56ea | 419 | |
f9bf01c6 A |
420 | // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor, |
421 | // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>. | |
422 | // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one. | |
423 | // The below function must be called by any inline function that invokes a JSString constructor. | |
424 | #if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore) | |
425 | inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; } | |
426 | #else | |
427 | inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; } | |
428 | #endif | |
429 | ||
ba379fdc | 430 | inline JSString* asString(JSValue value) |
9dae56ea | 431 | { |
14957cd0 A |
432 | ASSERT(value.asCell()->isString()); |
433 | return static_cast<JSString*>(value.asCell()); | |
9dae56ea A |
434 | } |
435 | ||
436 | inline JSString* jsEmptyString(JSGlobalData* globalData) | |
437 | { | |
438 | return globalData->smallStrings.emptyString(globalData); | |
439 | } | |
440 | ||
441 | inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) | |
442 | { | |
14957cd0 | 443 | if (c <= maxSingleCharacterString) |
9dae56ea | 444 | return globalData->smallStrings.singleCharacterString(globalData, c); |
f9bf01c6 | 445 | return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1))); |
9dae56ea A |
446 | } |
447 | ||
4e4e5a6f | 448 | inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) |
9dae56ea | 449 | { |
4e4e5a6f | 450 | JSGlobalData* globalData = &exec->globalData(); |
14957cd0 A |
451 | ASSERT(offset < static_cast<unsigned>(s.length())); |
452 | UChar c = s.characters()[offset]; | |
453 | if (c <= maxSingleCharacterString) | |
9dae56ea | 454 | return globalData->smallStrings.singleCharacterString(globalData, c); |
14957cd0 | 455 | return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, 1)))); |
9dae56ea A |
456 | } |
457 | ||
458 | inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) | |
459 | { | |
460 | ASSERT(s); | |
461 | ASSERT(s[0]); | |
462 | ASSERT(s[1]); | |
f9bf01c6 | 463 | return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); |
9dae56ea A |
464 | } |
465 | ||
466 | inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s) | |
467 | { | |
14957cd0 | 468 | ASSERT(s.length() > 1); |
f9bf01c6 | 469 | return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); |
9dae56ea A |
470 | } |
471 | ||
f9bf01c6 | 472 | inline JSString* JSString::getIndex(ExecState* exec, unsigned i) |
9dae56ea A |
473 | { |
474 | ASSERT(canGetIndex(i)); | |
4e4e5a6f A |
475 | if (isRope()) |
476 | return getIndexSlowCase(exec, i); | |
14957cd0 | 477 | ASSERT(i < m_value.length()); |
4e4e5a6f | 478 | return jsSingleCharacterSubstring(exec, m_value, i); |
f9bf01c6 A |
479 | } |
480 | ||
481 | inline JSString* jsString(JSGlobalData* globalData, const UString& s) | |
482 | { | |
14957cd0 | 483 | int size = s.length(); |
f9bf01c6 A |
484 | if (!size) |
485 | return globalData->smallStrings.emptyString(globalData); | |
486 | if (size == 1) { | |
14957cd0 A |
487 | UChar c = s.characters()[0]; |
488 | if (c <= maxSingleCharacterString) | |
f9bf01c6 A |
489 | return globalData->smallStrings.singleCharacterString(globalData, c); |
490 | } | |
491 | return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); | |
492 | } | |
493 | ||
b80e6193 A |
494 | inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) |
495 | { | |
496 | ASSERT(offset <= static_cast<unsigned>(s->length())); | |
497 | ASSERT(length <= static_cast<unsigned>(s->length())); | |
498 | ASSERT(offset + length <= static_cast<unsigned>(s->length())); | |
499 | JSGlobalData* globalData = &exec->globalData(); | |
500 | if (!length) | |
501 | return globalData->smallStrings.emptyString(globalData); | |
502 | if (s->isRope()) | |
503 | return s->substringFromRope(exec, offset, length); | |
504 | return jsSubstring(globalData, s->m_value, offset, length); | |
505 | } | |
f9bf01c6 A |
506 | |
507 | inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) | |
508 | { | |
14957cd0 A |
509 | ASSERT(offset <= static_cast<unsigned>(s.length())); |
510 | ASSERT(length <= static_cast<unsigned>(s.length())); | |
511 | ASSERT(offset + length <= static_cast<unsigned>(s.length())); | |
f9bf01c6 A |
512 | if (!length) |
513 | return globalData->smallStrings.emptyString(globalData); | |
514 | if (length == 1) { | |
14957cd0 A |
515 | UChar c = s.characters()[offset]; |
516 | if (c <= maxSingleCharacterString) | |
f9bf01c6 A |
517 | return globalData->smallStrings.singleCharacterString(globalData, c); |
518 | } | |
14957cd0 | 519 | return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, length)), JSString::HasOtherOwner)); |
f9bf01c6 A |
520 | } |
521 | ||
522 | inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) | |
523 | { | |
14957cd0 | 524 | int size = s.length(); |
f9bf01c6 A |
525 | if (!size) |
526 | return globalData->smallStrings.emptyString(globalData); | |
527 | if (size == 1) { | |
14957cd0 A |
528 | UChar c = s.characters()[0]; |
529 | if (c <= maxSingleCharacterString) | |
f9bf01c6 A |
530 | return globalData->smallStrings.singleCharacterString(globalData, c); |
531 | } | |
532 | return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner)); | |
9dae56ea A |
533 | } |
534 | ||
535 | inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } | |
536 | inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); } | |
537 | inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); } | |
9dae56ea A |
538 | inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); } |
539 | inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); } | |
540 | inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); } | |
541 | inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); } | |
542 | ||
543 | ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
544 | { | |
545 | if (propertyName == exec->propertyNames().length) { | |
14957cd0 | 546 | slot.setValue(jsNumber(m_length)); |
9dae56ea A |
547 | return true; |
548 | } | |
549 | ||
550 | bool isStrictUInt32; | |
14957cd0 | 551 | unsigned i = propertyName.toUInt32(isStrictUInt32); |
4e4e5a6f A |
552 | if (isStrictUInt32 && i < m_length) { |
553 | slot.setValue(getIndex(exec, i)); | |
9dae56ea A |
554 | return true; |
555 | } | |
556 | ||
557 | return false; | |
558 | } | |
559 | ||
560 | ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) | |
561 | { | |
4e4e5a6f A |
562 | if (propertyName < m_length) { |
563 | slot.setValue(getIndex(exec, propertyName)); | |
9dae56ea A |
564 | return true; |
565 | } | |
566 | ||
567 | return false; | |
568 | } | |
569 | ||
ba379fdc A |
570 | inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; } |
571 | ||
9dae56ea A |
572 | // --- JSValue inlines ---------------------------- |
573 | ||
f9bf01c6 A |
574 | inline UString JSValue::toString(ExecState* exec) const |
575 | { | |
576 | if (isString()) | |
577 | return static_cast<JSString*>(asCell())->value(exec); | |
578 | if (isInt32()) | |
579 | return exec->globalData().numericStrings.add(asInt32()); | |
580 | if (isDouble()) | |
581 | return exec->globalData().numericStrings.add(asDouble()); | |
582 | if (isTrue()) | |
583 | return "true"; | |
584 | if (isFalse()) | |
585 | return "false"; | |
586 | if (isNull()) | |
587 | return "null"; | |
588 | if (isUndefined()) | |
589 | return "undefined"; | |
590 | ASSERT(isCell()); | |
591 | return asCell()->toString(exec); | |
592 | } | |
593 | ||
594 | inline UString JSValue::toPrimitiveString(ExecState* exec) const | |
595 | { | |
14957cd0 | 596 | ASSERT(!isString()); |
f9bf01c6 A |
597 | if (isInt32()) |
598 | return exec->globalData().numericStrings.add(asInt32()); | |
599 | if (isDouble()) | |
600 | return exec->globalData().numericStrings.add(asDouble()); | |
601 | if (isTrue()) | |
602 | return "true"; | |
603 | if (isFalse()) | |
604 | return "false"; | |
605 | if (isNull()) | |
606 | return "null"; | |
607 | if (isUndefined()) | |
608 | return "undefined"; | |
609 | ASSERT(isCell()); | |
610 | return asCell()->toPrimitive(exec, NoPreference).toString(exec); | |
611 | } | |
612 | ||
9dae56ea A |
613 | } // namespace JSC |
614 | ||
615 | #endif // JSString_h |