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, 2014 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 "CallFrame.h"
27 #include "CommonIdentifiers.h"
28 #include "Identifier.h"
29 #include "PropertyDescriptor.h"
30 #include "PropertySlot.h"
31 #include "Structure.h"
33 #include <wtf/text/StringView.h>
39 class LLIntOffsetsExtractor
;
41 JSString
* jsEmptyString(VM
*);
42 JSString
* jsEmptyString(ExecState
*);
43 JSString
* jsString(VM
*, const String
&); // returns empty string if passed null string
44 JSString
* jsString(ExecState
*, const String
&); // returns empty string if passed null string
46 JSString
* jsSingleCharacterString(VM
*, UChar
);
47 JSString
* jsSingleCharacterString(ExecState
*, UChar
);
48 JSString
* jsSubstring(VM
*, const String
&, unsigned offset
, unsigned length
);
49 JSString
* jsSubstring(ExecState
*, const String
&, unsigned offset
, unsigned length
);
50 JSString
* jsSubstring8(VM
*, const String
&, unsigned offset
, unsigned length
);
51 JSString
* jsSubstring8(ExecState
*, const String
&, unsigned offset
, unsigned length
);
53 // Non-trivial strings are two or more characters long.
54 // These functions are faster than just calling jsString.
55 JSString
* jsNontrivialString(VM
*, const String
&);
56 JSString
* jsNontrivialString(ExecState
*, const String
&);
57 JSString
* jsNontrivialString(ExecState
*, String
&&);
59 // Should be used for strings that are owned by an object that will
60 // likely outlive the JSValue this makes, such as the parse tree or a
61 // DOM object that contains a String
62 JSString
* jsOwnedString(VM
*, const String
&);
63 JSString
* jsOwnedString(ExecState
*, const String
&);
65 JSRopeString
* jsStringBuilder(VM
*);
67 bool isJSString(JSValue
);
68 JSString
* asString(JSValue
);
70 struct StringViewWithUnderlyingString
{
72 String underlyingString
;
75 class JSString
: public JSCell
{
79 friend class SpecializedThunkJIT
;
80 friend class JSRopeString
;
81 friend class MarkStack
;
82 friend class SlotVisitor
;
83 friend struct ThunkHelpers
;
86 static const unsigned StructureFlags
= Base::StructureFlags
| OverridesGetOwnPropertySlot
| InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero
| StructureIsImmortal
;
88 static const bool needsDestruction
= true;
89 static void destroy(JSCell
*);
92 JSString(VM
& vm
, PassRefPtr
<StringImpl
> value
)
93 : JSCell(vm
, vm
.stringStructure
.get())
100 : JSCell(vm
, vm
.stringStructure
.get())
105 void finishCreation(VM
& vm
, size_t length
)
107 ASSERT(!m_value
.isNull());
108 Base::finishCreation(vm
);
110 setIs8Bit(m_value
.impl()->is8Bit());
111 vm
.m_newStringsSinceLastHashCons
++;
114 void finishCreation(VM
& vm
, size_t length
, size_t cost
)
116 ASSERT(!m_value
.isNull());
117 Base::finishCreation(vm
);
119 setIs8Bit(m_value
.impl()->is8Bit());
120 Heap::heap(this)->reportExtraMemoryAllocated(cost
);
121 vm
.m_newStringsSinceLastHashCons
++;
125 void finishCreation(VM
& vm
)
127 Base::finishCreation(vm
);
130 vm
.m_newStringsSinceLastHashCons
++;
134 static JSString
* create(VM
& vm
, PassRefPtr
<StringImpl
> value
)
137 int32_t length
= value
->length();
138 RELEASE_ASSERT(length
>= 0);
139 size_t cost
= value
->cost();
140 JSString
* newString
= new (NotNull
, allocateCell
<JSString
>(vm
.heap
)) JSString(vm
, value
);
141 newString
->finishCreation(vm
, length
, cost
);
144 static JSString
* createHasOtherOwner(VM
& vm
, PassRefPtr
<StringImpl
> value
)
147 size_t length
= value
->length();
148 JSString
* newString
= new (NotNull
, allocateCell
<JSString
>(vm
.heap
)) JSString(vm
, value
);
149 newString
->finishCreation(vm
, length
);
153 Identifier
toIdentifier(ExecState
*) const;
154 AtomicString
toAtomicString(ExecState
*) const;
155 RefPtr
<AtomicStringImpl
> toExistingAtomicString(ExecState
*) const;
158 SafeView
view(ExecState
*) const;
159 StringViewWithUnderlyingString
viewWithUnderlyingString(ExecState
&) const;
161 const String
& value(ExecState
*) const;
162 const String
& tryGetValue() const;
163 const StringImpl
* tryGetValueImpl() const;
164 unsigned length() const { return m_length
; }
166 JSValue
toPrimitive(ExecState
*, PreferredPrimitiveType
) const;
167 bool toBoolean() const { return !!m_length
; }
168 bool getPrimitiveNumber(ExecState
*, double& number
, JSValue
&) const;
169 JSObject
* toObject(ExecState
*, JSGlobalObject
*) const;
170 double toNumber(ExecState
*) const;
172 bool getStringPropertySlot(ExecState
*, PropertyName
, PropertySlot
&);
173 bool getStringPropertySlot(ExecState
*, unsigned propertyName
, PropertySlot
&);
174 bool getStringPropertyDescriptor(ExecState
*, PropertyName
, PropertyDescriptor
&);
176 bool canGetIndex(unsigned i
) { return i
< m_length
; }
177 JSString
* getIndex(ExecState
*, unsigned);
179 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue proto
)
181 return Structure::create(vm
, globalObject
, proto
, TypeInfo(StringType
, StructureFlags
), info());
184 static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString
, m_length
); }
185 static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString
, m_flags
); }
186 static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString
, m_value
); }
190 static void dumpToStream(const JSCell
*, PrintStream
&);
191 static void visitChildren(JSCell
*, SlotVisitor
&);
194 HashConsLock
= 1u << 2,
195 IsHashConsSingleton
= 1u << 1,
200 friend class JSValue
;
202 bool isRope() const { return m_value
.isNull(); }
203 bool isSubstring() const;
204 bool is8Bit() const { return m_flags
& Is8Bit
; }
205 void setIs8Bit(bool flag
) const
212 bool shouldTryHashCons();
213 bool isHashConsSingleton() const { return m_flags
& IsHashConsSingleton
; }
214 void clearHashConsSingleton() { m_flags
&= ~IsHashConsSingleton
; }
215 void setHashConsSingleton() { m_flags
|= IsHashConsSingleton
; }
216 bool tryHashConsLock();
217 void releaseHashConsLock();
219 mutable unsigned m_flags
;
221 // A string is represented either by a String or a rope of fibers.
223 mutable String m_value
;
226 friend class LLIntOffsetsExtractor
;
228 static JSValue
toThis(JSCell
*, ExecState
*, ECMAMode
);
230 String
& string() { ASSERT(!isRope()); return m_value
; }
231 StringView
unsafeView(ExecState
&) const;
233 friend JSValue
jsString(ExecState
*, JSString
*, JSString
*);
234 friend JSString
* jsSubstring(ExecState
*, JSString
*, unsigned offset
, unsigned length
);
237 class JSRopeString final
: public JSString
{
238 friend class JSString
;
240 friend JSRopeString
* jsStringBuilder(VM
*);
247 , m_jsString(jsStringBuilder(&vm
))
252 bool append(JSString
* jsString
)
254 if (m_index
== JSRopeString::s_maxInternalRopeLength
)
256 if (static_cast<int32_t>(m_jsString
->length() + jsString
->length()) < 0) {
257 m_jsString
= nullptr;
260 m_jsString
->append(m_vm
, m_index
++, jsString
);
264 JSRopeString
* release()
266 RELEASE_ASSERT(m_jsString
);
267 JSRopeString
* tmp
= m_jsString
;
272 unsigned length() const { return m_jsString
->m_length
; }
278 JSRopeString
* m_jsString
;
288 void finishCreation(VM
& vm
, JSString
* s1
, JSString
* s2
)
290 Base::finishCreation(vm
);
291 m_length
= s1
->length() + s2
->length();
292 setIs8Bit(s1
->is8Bit() && s2
->is8Bit());
293 setIsSubstring(false);
294 fiber(0).set(vm
, this, s1
);
295 fiber(1).set(vm
, this, s2
);
299 void finishCreation(VM
& vm
, JSString
* s1
, JSString
* s2
, JSString
* s3
)
301 Base::finishCreation(vm
);
302 m_length
= s1
->length() + s2
->length() + s3
->length();
303 setIs8Bit(s1
->is8Bit() && s2
->is8Bit() && s3
->is8Bit());
304 setIsSubstring(false);
305 fiber(0).set(vm
, this, s1
);
306 fiber(1).set(vm
, this, s2
);
307 fiber(2).set(vm
, this, s3
);
310 void finishCreation(ExecState
& exec
, JSString
& base
, unsigned offset
, unsigned length
)
313 Base::finishCreation(vm
);
314 ASSERT(!sumOverflows
<int32_t>(offset
, length
));
315 ASSERT(offset
+ length
<= base
.length());
317 setIs8Bit(base
.is8Bit());
318 setIsSubstring(true);
319 if (base
.isSubstring()) {
320 JSRopeString
& baseRope
= static_cast<JSRopeString
&>(base
);
321 substringBase().set(vm
, this, baseRope
.substringBase().get());
322 substringOffset() = baseRope
.substringOffset() + offset
;
324 substringBase().set(vm
, this, &base
);
325 substringOffset() = offset
;
327 // For now, let's not allow substrings with a rope base.
328 // Resolve non-substring rope bases so we don't have to deal with it.
329 // FIXME: Evaluate if this would be worth adding more branches.
331 static_cast<JSRopeString
&>(base
).resolveRope(&exec
);
335 void finishCreation(VM
& vm
)
337 JSString::finishCreation(vm
);
338 setIsSubstring(false);
344 void append(VM
& vm
, size_t index
, JSString
* jsString
)
346 fiber(index
).set(vm
, this, jsString
);
347 m_length
+= jsString
->m_length
;
348 RELEASE_ASSERT(static_cast<int32_t>(m_length
) >= 0);
349 setIs8Bit(is8Bit() && jsString
->is8Bit());
352 static JSRopeString
* createNull(VM
& vm
)
354 JSRopeString
* newString
= new (NotNull
, allocateCell
<JSRopeString
>(vm
.heap
)) JSRopeString(vm
);
355 newString
->finishCreation(vm
);
360 static JSString
* create(VM
& vm
, JSString
* s1
, JSString
* s2
)
362 JSRopeString
* newString
= new (NotNull
, allocateCell
<JSRopeString
>(vm
.heap
)) JSRopeString(vm
);
363 newString
->finishCreation(vm
, s1
, s2
);
366 static JSString
* create(VM
& vm
, JSString
* s1
, JSString
* s2
, JSString
* s3
)
368 JSRopeString
* newString
= new (NotNull
, allocateCell
<JSRopeString
>(vm
.heap
)) JSRopeString(vm
);
369 newString
->finishCreation(vm
, s1
, s2
, s3
);
373 static JSString
* create(ExecState
& exec
, JSString
& base
, unsigned offset
, unsigned length
)
375 JSRopeString
* newString
= new (NotNull
, allocateCell
<JSRopeString
>(exec
.vm().heap
)) JSRopeString(exec
.vm());
376 newString
->finishCreation(exec
, base
, offset
, length
);
380 void visitFibers(SlotVisitor
&);
382 static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString
, u
); }
384 static const unsigned s_maxInternalRopeLength
= 3;
387 friend JSValue
jsStringFromRegisterArray(ExecState
*, Register
*, unsigned);
388 friend JSValue
jsStringFromArguments(ExecState
*, JSValue
);
390 JS_EXPORT_PRIVATE
void resolveRope(ExecState
*) const;
391 JS_EXPORT_PRIVATE
void resolveRopeToAtomicString(ExecState
*) const;
392 JS_EXPORT_PRIVATE RefPtr
<AtomicStringImpl
> resolveRopeToExistingAtomicString(ExecState
*) const;
393 void resolveRopeSlowCase8(LChar
*) const;
394 void resolveRopeSlowCase(UChar
*) const;
395 void outOfMemory(ExecState
*) const;
396 void resolveRopeInternal8(LChar
*) const;
397 void resolveRopeInternal8NoSubstring(LChar
*) const;
398 void resolveRopeInternal16(UChar
*) const;
399 void resolveRopeInternal16NoSubstring(UChar
*) const;
400 void clearFibers() const;
401 StringView
unsafeView(ExecState
&) const;
402 StringViewWithUnderlyingString
viewWithUnderlyingString(ExecState
&) const;
404 WriteBarrierBase
<JSString
>& fiber(unsigned i
) const
406 ASSERT(!isSubstring());
407 ASSERT(i
< s_maxInternalRopeLength
);
411 WriteBarrierBase
<JSString
>& substringBase() const
416 uintptr_t& substringOffset() const
421 static uintptr_t notSubstringSentinel()
426 static uintptr_t substringSentinel()
431 bool isSubstring() const
433 return u
[0].number
== substringSentinel();
436 void setIsSubstring(bool isSubstring
)
438 u
[0].number
= isSubstring
? substringSentinel() : notSubstringSentinel();
443 WriteBarrierBase
<JSString
> string
;
444 } u
[s_maxInternalRopeLength
];
447 class JSString::SafeView
{
450 explicit SafeView(ExecState
&, const JSString
&);
451 operator StringView() const;
452 StringView
get() const;
455 ExecState
* m_state
{ nullptr };
457 // The following pointer is marked "volatile" to make the compiler leave it on the stack
458 // or in a register as long as this object is alive, even after the last use of the pointer.
459 // That's needed to prevent garbage collecting the string and possibly deleting the block
460 // with the characters in it, and then using the StringView after that.
461 const JSString
* volatile m_string
{ nullptr };
464 JS_EXPORT_PRIVATE JSString
* jsStringWithCacheSlowCase(VM
&, StringImpl
&);
466 inline const StringImpl
* JSString::tryGetValueImpl() const
468 return m_value
.impl();
471 inline JSString
* asString(JSValue value
)
473 ASSERT(value
.asCell()->isString());
474 return jsCast
<JSString
*>(value
.asCell());
477 inline JSString
* jsEmptyString(VM
* vm
)
479 return vm
->smallStrings
.emptyString();
482 ALWAYS_INLINE JSString
* jsSingleCharacterString(VM
* vm
, UChar c
)
484 if (c
<= maxSingleCharacterString
)
485 return vm
->smallStrings
.singleCharacterString(c
);
486 return JSString::create(*vm
, String(&c
, 1).impl());
489 inline JSString
* jsNontrivialString(VM
* vm
, const String
& s
)
491 ASSERT(s
.length() > 1);
492 return JSString::create(*vm
, s
.impl());
495 inline JSString
* jsNontrivialString(VM
* vm
, String
&& s
)
497 ASSERT(s
.length() > 1);
498 return JSString::create(*vm
, s
.releaseImpl());
501 ALWAYS_INLINE Identifier
JSString::toIdentifier(ExecState
* exec
) const
503 return Identifier::fromString(exec
, toAtomicString(exec
));
506 ALWAYS_INLINE AtomicString
JSString::toAtomicString(ExecState
* exec
) const
509 static_cast<const JSRopeString
*>(this)->resolveRopeToAtomicString(exec
);
510 return AtomicString(m_value
);
513 ALWAYS_INLINE RefPtr
<AtomicStringImpl
> JSString::toExistingAtomicString(ExecState
* exec
) const
516 return static_cast<const JSRopeString
*>(this)->resolveRopeToExistingAtomicString(exec
);
517 if (m_value
.impl()->isAtomic())
518 return static_cast<AtomicStringImpl
*>(m_value
.impl());
519 return AtomicStringImpl::lookUp(m_value
.impl());
522 inline const String
& JSString::value(ExecState
* exec
) const
525 static_cast<const JSRopeString
*>(this)->resolveRope(exec
);
529 inline const String
& JSString::tryGetValue() const
532 static_cast<const JSRopeString
*>(this)->resolveRope(0);
536 inline JSString
* JSString::getIndex(ExecState
* exec
, unsigned i
)
538 ASSERT(canGetIndex(i
));
539 return jsSingleCharacterString(exec
, unsafeView(*exec
)[i
]);
542 inline JSString
* jsString(VM
* vm
, const String
& s
)
544 int size
= s
.length();
546 return vm
->smallStrings
.emptyString();
548 UChar c
= s
.characterAt(0);
549 if (c
<= maxSingleCharacterString
)
550 return vm
->smallStrings
.singleCharacterString(c
);
552 return JSString::create(*vm
, s
.impl());
555 inline JSString
* jsSubstring(ExecState
* exec
, JSString
* s
, unsigned offset
, unsigned length
)
557 ASSERT(offset
<= static_cast<unsigned>(s
->length()));
558 ASSERT(length
<= static_cast<unsigned>(s
->length()));
559 ASSERT(offset
+ length
<= static_cast<unsigned>(s
->length()));
562 return vm
.smallStrings
.emptyString();
563 if (!offset
&& length
== s
->length())
565 return JSRopeString::create(*exec
, *s
, offset
, length
);
568 inline JSString
* jsSubstring8(VM
* vm
, const String
& s
, unsigned offset
, unsigned length
)
570 ASSERT(offset
<= static_cast<unsigned>(s
.length()));
571 ASSERT(length
<= static_cast<unsigned>(s
.length()));
572 ASSERT(offset
+ length
<= static_cast<unsigned>(s
.length()));
574 return vm
->smallStrings
.emptyString();
576 UChar c
= s
.characterAt(offset
);
577 if (c
<= maxSingleCharacterString
)
578 return vm
->smallStrings
.singleCharacterString(c
);
580 return JSString::createHasOtherOwner(*vm
, StringImpl::createSubstringSharingImpl8(s
.impl(), offset
, length
));
583 inline JSString
* jsSubstring(VM
* vm
, const String
& s
, unsigned offset
, unsigned length
)
585 ASSERT(offset
<= static_cast<unsigned>(s
.length()));
586 ASSERT(length
<= static_cast<unsigned>(s
.length()));
587 ASSERT(offset
+ length
<= static_cast<unsigned>(s
.length()));
589 return vm
->smallStrings
.emptyString();
591 UChar c
= s
.characterAt(offset
);
592 if (c
<= maxSingleCharacterString
)
593 return vm
->smallStrings
.singleCharacterString(c
);
595 return JSString::createHasOtherOwner(*vm
, StringImpl::createSubstringSharingImpl(s
.impl(), offset
, length
));
598 inline JSString
* jsOwnedString(VM
* vm
, const String
& s
)
600 int size
= s
.length();
602 return vm
->smallStrings
.emptyString();
604 UChar c
= s
.characterAt(0);
605 if (c
<= maxSingleCharacterString
)
606 return vm
->smallStrings
.singleCharacterString(c
);
608 return JSString::createHasOtherOwner(*vm
, s
.impl());
611 inline JSRopeString
* jsStringBuilder(VM
* vm
)
613 return JSRopeString::createNull(*vm
);
616 inline JSString
* jsEmptyString(ExecState
* exec
) { return jsEmptyString(&exec
->vm()); }
617 inline JSString
* jsString(ExecState
* exec
, const String
& s
) { return jsString(&exec
->vm(), s
); }
618 inline JSString
* jsSingleCharacterString(ExecState
* exec
, UChar c
) { return jsSingleCharacterString(&exec
->vm(), c
); }
619 inline JSString
* jsSubstring8(ExecState
* exec
, const String
& s
, unsigned offset
, unsigned length
) { return jsSubstring8(&exec
->vm(), s
, offset
, length
); }
620 inline JSString
* jsSubstring(ExecState
* exec
, const String
& s
, unsigned offset
, unsigned length
) { return jsSubstring(&exec
->vm(), s
, offset
, length
); }
621 inline JSString
* jsNontrivialString(ExecState
* exec
, const String
& s
) { return jsNontrivialString(&exec
->vm(), s
); }
622 inline JSString
* jsNontrivialString(ExecState
* exec
, String
&& s
) { return jsNontrivialString(&exec
->vm(), WTF::move(s
)); }
623 inline JSString
* jsOwnedString(ExecState
* exec
, const String
& s
) { return jsOwnedString(&exec
->vm(), s
); }
625 ALWAYS_INLINE JSString
* jsStringWithCache(ExecState
* exec
, const String
& s
)
628 StringImpl
* stringImpl
= s
.impl();
629 if (!stringImpl
|| !stringImpl
->length())
630 return jsEmptyString(&vm
);
632 if (stringImpl
->length() == 1) {
633 UChar singleCharacter
= (*stringImpl
)[0u];
634 if (singleCharacter
<= maxSingleCharacterString
)
635 return vm
.smallStrings
.singleCharacterString(static_cast<unsigned char>(singleCharacter
));
638 if (JSString
* lastCachedString
= vm
.lastCachedString
.get()) {
639 if (lastCachedString
->tryGetValueImpl() == stringImpl
)
640 return lastCachedString
;
643 return jsStringWithCacheSlowCase(vm
, *stringImpl
);
646 ALWAYS_INLINE JSString
* jsStringWithCache(ExecState
* exec
, const AtomicString
& s
)
648 return jsStringWithCache(exec
, s
.string());
651 ALWAYS_INLINE
bool JSString::getStringPropertySlot(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
653 if (propertyName
== exec
->propertyNames().length
) {
654 slot
.setValue(this, DontEnum
| DontDelete
| ReadOnly
, jsNumber(m_length
));
658 Optional
<uint32_t> index
= parseIndex(propertyName
);
659 if (index
&& index
.value() < m_length
) {
660 slot
.setValue(this, DontDelete
| ReadOnly
, getIndex(exec
, index
.value()));
667 ALWAYS_INLINE
bool JSString::getStringPropertySlot(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
669 if (propertyName
< m_length
) {
670 slot
.setValue(this, DontDelete
| ReadOnly
, getIndex(exec
, propertyName
));
677 inline bool isJSString(JSValue v
)
679 return v
.isCell() && v
.asCell()->type() == StringType
;
682 ALWAYS_INLINE StringView
JSRopeString::unsafeView(ExecState
& state
) const
686 return StringView(substringBase()->m_value
.characters8() + substringOffset(), m_length
);
687 return StringView(substringBase()->m_value
.characters16() + substringOffset(), m_length
);
693 ALWAYS_INLINE StringViewWithUnderlyingString
JSRopeString::viewWithUnderlyingString(ExecState
& state
) const
696 auto& base
= substringBase()->m_value
;
698 return { { base
.characters8() + substringOffset(), m_length
}, base
};
699 return { { base
.characters16() + substringOffset(), m_length
}, base
};
702 return { m_value
, m_value
};
705 ALWAYS_INLINE StringView
JSString::unsafeView(ExecState
& state
) const
708 return static_cast<const JSRopeString
*>(this)->unsafeView(state
);
712 ALWAYS_INLINE StringViewWithUnderlyingString
JSString::viewWithUnderlyingString(ExecState
& state
) const
715 return static_cast<const JSRopeString
&>(*this).viewWithUnderlyingString(state
);
716 return { m_value
, m_value
};
719 inline bool JSString::isSubstring() const
721 return isRope() && static_cast<const JSRopeString
*>(this)->isSubstring();
724 inline JSString::SafeView::SafeView()
728 inline JSString::SafeView::SafeView(ExecState
& state
, const JSString
& string
)
734 inline JSString::SafeView::operator StringView() const
736 return m_string
->unsafeView(*m_state
);
739 inline StringView
JSString::SafeView::get() const
744 ALWAYS_INLINE
JSString::SafeView
JSString::view(ExecState
* exec
) const
746 return SafeView(*exec
, *this);
749 // --- JSValue inlines ----------------------------
751 inline bool JSValue::toBoolean(ExecState
* exec
) const
756 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
758 return asCell()->toBoolean(exec
);
759 return isTrue(); // false, null, and undefined all convert to false.
762 inline JSString
* JSValue::toString(ExecState
* exec
) const
765 return jsCast
<JSString
*>(asCell());
766 return toStringSlowCase(exec
);
769 inline String
JSValue::toWTFString(ExecState
* exec
) const
772 return static_cast<JSString
*>(asCell())->value(exec
);
773 return toWTFStringSlowCase(exec
);