]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSString.h
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / runtime / JSString.h
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4be4e309 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
9dae56ea
A
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
81345200 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"
14957cd0 31#include "Structure.h"
81345200 32#include <array>
9dae56ea
A
33
34namespace JSC {
35
81345200
A
36 class JSString;
37 class JSRopeString;
38 class LLIntOffsetsExtractor;
9dae56ea 39
81345200
A
40 JSString* jsEmptyString(VM*);
41 JSString* jsEmptyString(ExecState*);
42 JSString* jsString(VM*, const String&); // returns empty string if passed null string
43 JSString* jsString(ExecState*, const String&); // returns empty string if passed null string
f9bf01c6 44
81345200
A
45 JSString* jsSingleCharacterString(VM*, UChar);
46 JSString* jsSingleCharacterString(ExecState*, UChar);
47 JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset);
48 JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
49 JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
4e4e5a6f 50
81345200
A
51 // Non-trivial strings are two or more characters long.
52 // These functions are faster than just calling jsString.
53 JSString* jsNontrivialString(VM*, const String&);
54 JSString* jsNontrivialString(ExecState*, const String&);
4e4e5a6f 55
81345200
A
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 String
59 JSString* jsOwnedString(VM*, const String&);
60 JSString* jsOwnedString(ExecState*, const String&);
6fe7ccc8 61
81345200 62 JSRopeString* jsStringBuilder(VM*);
9dae56ea 63
81345200
A
64 class JSString : public JSCell {
65 public:
66 friend class JIT;
67 friend class VM;
68 friend class SpecializedThunkJIT;
69 friend class JSRopeString;
70 friend class MarkStack;
71 friend class SlotVisitor;
72 friend struct ThunkHelpers;
9dae56ea 73
81345200 74 typedef JSCell Base;
9dae56ea 75
81345200
A
76 static const bool needsDestruction = true;
77 static const bool hasImmortalStructure = true;
78 static void destroy(JSCell*);
79
80 private:
81 JSString(VM& vm, PassRefPtr<StringImpl> value)
82 : JSCell(vm, vm.stringStructure.get())
83 , m_flags(0)
84 , m_value(value)
85 {
86 }
87
88 JSString(VM& vm)
89 : JSCell(vm, vm.stringStructure.get())
90 , m_flags(0)
91 {
92 }
93
94 void finishCreation(VM& vm, size_t length)
95 {
96 ASSERT(!m_value.isNull());
97 Base::finishCreation(vm);
98 m_length = length;
99 setIs8Bit(m_value.impl()->is8Bit());
100 vm.m_newStringsSinceLastHashCons++;
101 }
102
103 void finishCreation(VM& vm, size_t length, size_t cost)
104 {
105 ASSERT(!m_value.isNull());
106 Base::finishCreation(vm);
107 m_length = length;
108 setIs8Bit(m_value.impl()->is8Bit());
109 Heap::heap(this)->reportExtraMemoryCost(cost);
110 vm.m_newStringsSinceLastHashCons++;
111 }
112
113 protected:
114 void finishCreation(VM& vm)
115 {
116 Base::finishCreation(vm);
117 m_length = 0;
118 setIs8Bit(true);
119 vm.m_newStringsSinceLastHashCons++;
120 }
121
122 public:
123 static JSString* create(VM& vm, PassRefPtr<StringImpl> value)
124 {
125 ASSERT(value);
126 int32_t length = value->length();
127 RELEASE_ASSERT(length >= 0);
128 size_t cost = value->cost();
129 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
130 newString->finishCreation(vm, length, cost);
131 return newString;
132 }
133 static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value)
134 {
135 ASSERT(value);
136 size_t length = value->length();
137 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
138 newString->finishCreation(vm, length);
139 return newString;
140 }
141
142 Identifier toIdentifier(ExecState*) const;
143 AtomicString toAtomicString(ExecState*) const;
144 AtomicStringImpl* toExistingAtomicString(ExecState*) const;
145 const String& value(ExecState*) const;
146 const String& tryGetValue() const;
147 const StringImpl* tryGetValueImpl() const;
148 unsigned length() const { return m_length; }
149
150 JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
151 JS_EXPORT_PRIVATE bool toBoolean() const;
152 bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
153 JSObject* toObject(ExecState*, JSGlobalObject*) const;
154 double toNumber(ExecState*) const;
155
156 bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&);
157 bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
158 bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
159
160 bool canGetIndex(unsigned i) { return i < m_length; }
161 JSString* getIndex(ExecState*, unsigned);
6fe7ccc8 162
81345200
A
163 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
164 {
165 return Structure::create(vm, globalObject, proto, TypeInfo(StringType, StructureFlags), info());
166 }
167
168 static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
169 static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); }
170 static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
171
172 DECLARE_EXPORT_INFO;
173
174 static void dumpToStream(const JSCell*, PrintStream&);
175 static void visitChildren(JSCell*, SlotVisitor&);
176
177 enum {
178 HashConsLock = 1u << 2,
179 IsHashConsSingleton = 1u << 1,
180 Is8Bit = 1u
181 };
6fe7ccc8 182
81345200
A
183 protected:
184 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal;
6fe7ccc8 185
81345200
A
186 friend class JSValue;
187
188 bool isRope() const { return m_value.isNull(); }
189 bool is8Bit() const { return m_flags & Is8Bit; }
190 void setIs8Bit(bool flag)
191 {
192 if (flag)
193 m_flags |= Is8Bit;
194 else
195 m_flags &= ~Is8Bit;
196 }
197 bool shouldTryHashCons();
198 bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; }
199 void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; }
200 void setHashConsSingleton() { m_flags |= IsHashConsSingleton; }
201 bool tryHashConsLock();
202 void releaseHashConsLock();
203
204 unsigned m_flags;
205
206 // A string is represented either by a String or a rope of fibers.
207 unsigned m_length;
208 mutable String m_value;
6fe7ccc8 209
81345200
A
210 private:
211 friend class LLIntOffsetsExtractor;
212
213 static JSValue toThis(JSCell*, ExecState*, ECMAMode);
214
215 String& string() { ASSERT(!isRope()); return m_value; }
216
217 friend JSValue jsString(ExecState*, JSString*, JSString*);
218 friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
93a37866 219 };
6fe7ccc8 220
81345200
A
221 class JSRopeString : public JSString {
222 friend class JSString;
6fe7ccc8 223
81345200 224 friend JSRopeString* jsStringBuilder(VM*);
6fe7ccc8 225
81345200
A
226 class RopeBuilder {
227 public:
228 RopeBuilder(VM& vm)
229 : m_vm(vm)
230 , m_jsString(jsStringBuilder(&vm))
231 , m_index(0)
232 {
233 }
6fe7ccc8 234
81345200
A
235 bool append(JSString* jsString)
236 {
237 if (m_index == JSRopeString::s_maxInternalRopeLength)
238 expand();
239 if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
240 m_jsString = nullptr;
241 return false;
242 }
243 m_jsString->append(m_vm, m_index++, jsString);
244 return true;
245 }
6fe7ccc8 246
81345200
A
247 JSRopeString* release()
248 {
249 RELEASE_ASSERT(m_jsString);
250 JSRopeString* tmp = m_jsString;
251 m_jsString = 0;
252 return tmp;
253 }
6fe7ccc8 254
81345200 255 unsigned length() const { return m_jsString->m_length; }
9dae56ea 256
81345200
A
257 private:
258 void expand();
259
260 VM& m_vm;
261 JSRopeString* m_jsString;
262 size_t m_index;
263 };
264
265 private:
266 JSRopeString(VM& vm)
267 : JSString(vm)
268 {
269 }
6fe7ccc8 270
81345200 271 void finishCreation(VM& vm, JSString* s1, JSString* s2)
f9bf01c6 272 {
81345200
A
273 Base::finishCreation(vm);
274 m_length = s1->length() + s2->length();
275 setIs8Bit(s1->is8Bit() && s2->is8Bit());
276 m_fibers[0].set(vm, this, s1);
277 m_fibers[1].set(vm, this, s2);
278 }
279
280 void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3)
281 {
282 Base::finishCreation(vm);
283 m_length = s1->length() + s2->length() + s3->length();
284 setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
285 m_fibers[0].set(vm, this, s1);
286 m_fibers[1].set(vm, this, s2);
287 m_fibers[2].set(vm, this, s3);
f9bf01c6
A
288 }
289
81345200 290 void finishCreation(VM& vm)
6fe7ccc8 291 {
81345200
A
292 JSString::finishCreation(vm);
293 }
294
295 void append(VM& vm, size_t index, JSString* jsString)
296 {
297 m_fibers[index].set(vm, this, jsString);
298 m_length += jsString->m_length;
299 RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
300 setIs8Bit(is8Bit() && jsString->is8Bit());
6fe7ccc8 301 }
f9bf01c6 302
81345200 303 static JSRopeString* createNull(VM& vm)
f9bf01c6 304 {
81345200
A
305 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
306 newString->finishCreation(vm);
307 return newString;
f9bf01c6
A
308 }
309
81345200
A
310 public:
311 static JSString* create(VM& vm, JSString* s1, JSString* s2)
312 {
313 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
314 newString->finishCreation(vm, s1, s2);
315 return newString;
316 }
317 static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
318 {
319 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
320 newString->finishCreation(vm, s1, s2, s3);
321 return newString;
322 }
9dae56ea 323
81345200
A
324 void visitFibers(SlotVisitor&);
325
326 static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); }
327
328 static const unsigned s_maxInternalRopeLength = 3;
329
6fe7ccc8 330 private:
81345200
A
331 friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned);
332 friend JSValue jsStringFromArguments(ExecState*, JSValue);
333
334 JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
335 JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const;
336 JS_EXPORT_PRIVATE AtomicStringImpl* resolveRopeToExistingAtomicString(ExecState*) const;
337 void resolveRopeSlowCase8(LChar*) const;
338 void resolveRopeSlowCase(UChar*) const;
339 void outOfMemory(ExecState*) const;
340 void resolveRopeInternal8(LChar*) const;
341 void resolveRopeInternal16(UChar*) const;
342 void clearFibers() const;
93a37866 343
81345200
A
344 JS_EXPORT_PRIVATE JSString* getIndexSlowCase(ExecState*, unsigned);
345
346 mutable std::array<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
9dae56ea 347 };
81345200
A
348
349
350 inline const StringImpl* JSString::tryGetValueImpl() const
9dae56ea 351 {
81345200 352 return m_value.impl();
9dae56ea
A
353 }
354
81345200
A
355 JSString* asString(JSValue);
356
357 inline JSString* asString(JSValue value)
9dae56ea 358 {
81345200
A
359 ASSERT(value.asCell()->isString());
360 return jsCast<JSString*>(value.asCell());
9dae56ea 361 }
81345200
A
362
363 inline JSString* jsEmptyString(VM* vm)
9dae56ea 364 {
81345200 365 return vm->smallStrings.emptyString();
9dae56ea
A
366 }
367
81345200 368 ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
9dae56ea 369 {
81345200
A
370 if (c <= maxSingleCharacterString)
371 return vm->smallStrings.singleCharacterString(c);
372 return JSString::create(*vm, String(&c, 1).impl());
9dae56ea
A
373 }
374
81345200 375 ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset)
9dae56ea 376 {
81345200
A
377 VM* vm = &exec->vm();
378 ASSERT(offset < static_cast<unsigned>(s.length()));
379 UChar c = s.characterAt(offset);
380 if (c <= maxSingleCharacterString)
381 return vm->smallStrings.singleCharacterString(c);
382 return JSString::create(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, 1));
9dae56ea
A
383 }
384
81345200 385 inline JSString* jsNontrivialString(VM* vm, const String& s)
9dae56ea 386 {
81345200
A
387 ASSERT(s.length() > 1);
388 return JSString::create(*vm, s.impl());
6fe7ccc8
A
389 }
390
81345200 391 ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const
6fe7ccc8 392 {
81345200 393 return Identifier(exec, toAtomicString(exec));
6fe7ccc8 394 }
81345200
A
395
396 ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const
6fe7ccc8 397 {
81345200
A
398 if (isRope())
399 static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
400 return AtomicString(m_value);
9dae56ea
A
401 }
402
81345200
A
403 ALWAYS_INLINE AtomicStringImpl* JSString::toExistingAtomicString(ExecState* exec) const
404 {
405 if (isRope())
406 return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec);
407 if (m_value.impl()->isAtomic())
408 return static_cast<AtomicStringImpl*>(m_value.impl());
409 if (AtomicStringImpl* existingAtomicString = AtomicString::find(m_value.impl())) {
410 m_value = *existingAtomicString;
411 return existingAtomicString;
412 }
413 return nullptr;
414 }
f9bf01c6 415
81345200
A
416 inline const String& JSString::value(ExecState* exec) const
417 {
418 if (isRope())
419 static_cast<const JSRopeString*>(this)->resolveRope(exec);
420 return m_value;
f9bf01c6 421 }
81345200
A
422
423 inline const String& JSString::tryGetValue() const
424 {
425 if (isRope())
426 static_cast<const JSRopeString*>(this)->resolveRope(0);
427 return m_value;
6fe7ccc8 428 }
81345200
A
429
430 inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
431 {
432 ASSERT(canGetIndex(i));
433 if (isRope())
434 return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i);
435 ASSERT(i < m_value.length());
436 return jsSingleCharacterSubstring(exec, m_value, i);
b80e6193 437 }
93a37866 438
81345200
A
439 inline JSString* jsString(VM* vm, const String& s)
440 {
441 int size = s.length();
442 if (!size)
443 return vm->smallStrings.emptyString();
444 if (size == 1) {
445 UChar c = s.characterAt(0);
446 if (c <= maxSingleCharacterString)
447 return vm->smallStrings.singleCharacterString(c);
448 }
449 return JSString::create(*vm, s.impl());
450 }
451
452 inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
453 {
454 ASSERT(offset <= static_cast<unsigned>(s->length()));
455 ASSERT(length <= static_cast<unsigned>(s->length()));
456 ASSERT(offset + length <= static_cast<unsigned>(s->length()));
457 VM* vm = &exec->vm();
458 if (!length)
459 return vm->smallStrings.emptyString();
460 return jsSubstring(vm, s->value(exec), offset, length);
461 }
462
463 inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length)
464 {
465 ASSERT(offset <= static_cast<unsigned>(s.length()));
466 ASSERT(length <= static_cast<unsigned>(s.length()));
467 ASSERT(offset + length <= static_cast<unsigned>(s.length()));
468 if (!length)
469 return vm->smallStrings.emptyString();
470 if (length == 1) {
471 UChar c = s.characterAt(offset);
472 if (c <= maxSingleCharacterString)
473 return vm->smallStrings.singleCharacterString(c);
474 }
475 return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl8(s.impl(), offset, length));
476 }
477
478 inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
479 {
480 ASSERT(offset <= static_cast<unsigned>(s.length()));
481 ASSERT(length <= static_cast<unsigned>(s.length()));
482 ASSERT(offset + length <= static_cast<unsigned>(s.length()));
483 if (!length)
484 return vm->smallStrings.emptyString();
485 if (length == 1) {
486 UChar c = s.characterAt(offset);
487 if (c <= maxSingleCharacterString)
488 return vm->smallStrings.singleCharacterString(c);
489 }
490 return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, length));
f9bf01c6 491 }
81345200
A
492
493 inline JSString* jsOwnedString(VM* vm, const String& s)
494 {
495 int size = s.length();
496 if (!size)
497 return vm->smallStrings.emptyString();
498 if (size == 1) {
499 UChar c = s.characterAt(0);
500 if (c <= maxSingleCharacterString)
501 return vm->smallStrings.singleCharacterString(c);
502 }
503 return JSString::createHasOtherOwner(*vm, s.impl());
6fe7ccc8
A
504 }
505
81345200
A
506 inline JSRopeString* jsStringBuilder(VM* vm)
507 {
508 return JSRopeString::createNull(*vm);
9dae56ea
A
509 }
510
81345200
A
511 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
512 inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
513 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
514 inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); }
515 inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
516 inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
517 inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
518
519 JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&);
520
521 ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s)
522 {
523 VM& vm = exec->vm();
524 StringImpl* stringImpl = s.impl();
525 if (!stringImpl || !stringImpl->length())
526 return jsEmptyString(&vm);
527
528 if (stringImpl->length() == 1) {
529 UChar singleCharacter = (*stringImpl)[0u];
530 if (singleCharacter <= maxSingleCharacterString)
531 return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
532 }
533
534 if (JSString* lastCachedString = vm.lastCachedString.get()) {
535 if (lastCachedString->tryGetValueImpl() == stringImpl)
536 return lastCachedString;
537 }
538
539 return jsStringWithCacheSlowCase(vm, *stringImpl);
540 }
541
542 ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const AtomicString& s)
543 {
544 return jsStringWithCache(exec, s.string());
545 }
546
547 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
548 {
549 if (propertyName == exec->propertyNames().length) {
550 slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length));
551 return true;
552 }
553
554 unsigned i = propertyName.asIndex();
555 if (i < m_length) {
556 ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
557 slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, i));
558 return true;
559 }
560
561 return false;
562 }
563
564 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
565 {
566 if (propertyName < m_length) {
567 slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName));
568 return true;
569 }
570
571 return false;
572 }
573
574 inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->type() == StringType; }
575
576 // --- JSValue inlines ----------------------------
9dae56ea 577
81345200
A
578 inline bool JSValue::toBoolean(ExecState* exec) const
579 {
580 if (isInt32())
581 return asInt32();
582 if (isDouble())
583 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
584 if (isCell())
585 return asCell()->toBoolean(exec);
586 return isTrue(); // false, null, and undefined all convert to false.
587 }
588
589 inline JSString* JSValue::toString(ExecState* exec) const
590 {
591 if (isString())
592 return jsCast<JSString*>(asCell());
593 return toStringSlowCase(exec);
594 }
595
596 inline String JSValue::toWTFString(ExecState* exec) const
597 {
598 if (isString())
599 return static_cast<JSString*>(asCell())->value(exec);
600 return toWTFStringSlowCase(exec);
9dae56ea
A
601 }
602
81345200
A
603 ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec)
604 {
605 VM& vm = exec->vm();
606 if (value.isInt32())
607 return vm.numericStrings.add(value.asInt32());
608 if (value.isDouble())
609 return vm.numericStrings.add(value.asDouble());
610 if (value.isTrue())
611 return vm.propertyNames->trueKeyword.string();
612 if (value.isFalse())
613 return vm.propertyNames->falseKeyword.string();
614 if (value.isNull())
615 return vm.propertyNames->nullKeyword.string();
616 if (value.isUndefined())
617 return vm.propertyNames->undefinedKeyword.string();
618 return value.toString(exec)->value(exec);
619 }
620
621 ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const
622 {
623 if (isString())
624 return static_cast<JSString*>(asCell())->value(exec);
625
626 return inlineJSValueNotStringtoString(*this, exec);
627 }
f9bf01c6 628
9dae56ea
A
629} // namespace JSC
630
631#endif // JSString_h