Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSString.h
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, 2014 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
26 #include "CallFrame.h"
27 #include "CommonIdentifiers.h"
28 #include "Identifier.h"
29 #include "PropertyDescriptor.h"
30 #include "PropertySlot.h"
31 #include "Structure.h"
32 #include <array>
33 #include <wtf/text/StringView.h>
34
35 namespace JSC {
36
37 class JSString;
38 class JSRopeString;
39 class LLIntOffsetsExtractor;
40
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
45
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);
52
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&&);
58
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&);
64
65 JSRopeString* jsStringBuilder(VM*);
66
67 bool isJSString(JSValue);
68 JSString* asString(JSValue);
69
70 struct StringViewWithUnderlyingString {
71     StringView view;
72     String underlyingString;
73 };
74
75 class JSString : public JSCell {
76 public:
77     friend class JIT;
78     friend class VM;
79     friend class SpecializedThunkJIT;
80     friend class JSRopeString;
81     friend class MarkStack;
82     friend class SlotVisitor;
83     friend struct ThunkHelpers;
84
85     typedef JSCell Base;
86     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal;
87
88     static const bool needsDestruction = true;
89     static void destroy(JSCell*);
90
91 private:
92     JSString(VM& vm, PassRefPtr<StringImpl> value)
93         : JSCell(vm, vm.stringStructure.get())
94         , m_flags(0)
95         , m_value(value)
96     {
97     }
98
99     JSString(VM& vm)
100         : JSCell(vm, vm.stringStructure.get())
101         , m_flags(0)
102     {
103     }
104
105     void finishCreation(VM& vm, size_t length)
106     {
107         ASSERT(!m_value.isNull());
108         Base::finishCreation(vm);
109         m_length = length;
110         setIs8Bit(m_value.impl()->is8Bit());
111     }
112
113     void finishCreation(VM& vm, size_t length, size_t cost)
114     {
115         ASSERT(!m_value.isNull());
116         Base::finishCreation(vm);
117         m_length = length;
118         setIs8Bit(m_value.impl()->is8Bit());
119         Heap::heap(this)->reportExtraMemoryAllocated(cost);
120     }
121
122 protected:
123     void finishCreation(VM& vm)
124     {
125         Base::finishCreation(vm);
126         m_length = 0;
127         setIs8Bit(true);
128     }
129
130 public:
131     static JSString* create(VM& vm, PassRefPtr<StringImpl> value)
132     {
133         ASSERT(value);
134         int32_t length = value->length();
135         RELEASE_ASSERT(length >= 0);
136         size_t cost = value->cost();
137         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
138         newString->finishCreation(vm, length, cost);
139         return newString;
140     }
141     static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value)
142     {
143         ASSERT(value);
144         size_t length = value->length();
145         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
146         newString->finishCreation(vm, length);
147         return newString;
148     }
149
150     Identifier toIdentifier(ExecState*) const;
151     AtomicString toAtomicString(ExecState*) const;
152     RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const;
153
154     class SafeView;
155     SafeView view(ExecState*) const;
156     StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const;
157
158     const String& value(ExecState*) const;
159     const String& tryGetValue() const;
160     const StringImpl* tryGetValueImpl() const;
161     unsigned length() const { return m_length; }
162
163     JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
164     bool toBoolean() const { return !!m_length; }
165     bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
166     JSObject* toObject(ExecState*, JSGlobalObject*) const;
167     double toNumber(ExecState*) const;
168
169     bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&);
170     bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
171     bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
172
173     bool canGetIndex(unsigned i) { return i < m_length; }
174     JSString* getIndex(ExecState*, unsigned);
175
176     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
177
178     static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
179     static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); }
180     static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
181
182     DECLARE_EXPORT_INFO;
183
184     static void dumpToStream(const JSCell*, PrintStream&);
185     static void visitChildren(JSCell*, SlotVisitor&);
186
187     enum {
188         Is8Bit = 1u
189     };
190
191 protected:
192     friend class JSValue;
193
194     bool isRope() const { return m_value.isNull(); }
195     bool isSubstring() const;
196     bool is8Bit() const { return m_flags & Is8Bit; }
197     void setIs8Bit(bool flag) const
198     {
199         if (flag)
200             m_flags |= Is8Bit;
201         else
202             m_flags &= ~Is8Bit;
203     }
204
205     mutable unsigned m_flags;
206
207     // A string is represented either by a String or a rope of fibers.
208     unsigned m_length;
209     mutable String m_value;
210
211 private:
212     friend class LLIntOffsetsExtractor;
213
214     static JSValue toThis(JSCell*, ExecState*, ECMAMode);
215
216     String& string() { ASSERT(!isRope()); return m_value; }
217     StringView unsafeView(ExecState&) const;
218
219     friend JSValue jsString(ExecState*, JSString*, JSString*);
220     friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
221 };
222
223 class JSRopeString final : public JSString {
224     friend class JSString;
225
226     friend JSRopeString* jsStringBuilder(VM*);
227
228 public:
229     class RopeBuilder {
230     public:
231         RopeBuilder(VM& vm)
232             : m_vm(vm)
233             , m_jsString(jsStringBuilder(&vm))
234             , m_index(0)
235         {
236         }
237
238         bool append(JSString* jsString)
239         {
240             if (m_index == JSRopeString::s_maxInternalRopeLength)
241                 expand();
242             if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
243                 m_jsString = nullptr;
244                 return false;
245             }
246             m_jsString->append(m_vm, m_index++, jsString);
247             return true;
248         }
249
250         JSRopeString* release()
251         {
252             RELEASE_ASSERT(m_jsString);
253             JSRopeString* tmp = m_jsString;
254             m_jsString = 0;
255             return tmp;
256         }
257
258         unsigned length() const { return m_jsString->m_length; }
259
260     private:
261         void expand();
262
263         VM& m_vm;
264         JSRopeString* m_jsString;
265         size_t m_index;
266     };
267
268 private:
269     JSRopeString(VM& vm)
270         : JSString(vm)
271     {
272     }
273
274     void finishCreation(VM& vm, JSString* s1, JSString* s2)
275     {
276         Base::finishCreation(vm);
277         m_length = s1->length() + s2->length();
278         setIs8Bit(s1->is8Bit() && s2->is8Bit());
279         setIsSubstring(false);
280         fiber(0).set(vm, this, s1);
281         fiber(1).set(vm, this, s2);
282         fiber(2).clear();
283     }
284
285     void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3)
286     {
287         Base::finishCreation(vm);
288         m_length = s1->length() + s2->length() + s3->length();
289         setIs8Bit(s1->is8Bit() && s2->is8Bit() &&  s3->is8Bit());
290         setIsSubstring(false);
291         fiber(0).set(vm, this, s1);
292         fiber(1).set(vm, this, s2);
293         fiber(2).set(vm, this, s3);
294     }
295
296     void finishCreation(ExecState& exec, JSString& base, unsigned offset, unsigned length)
297     {
298         VM& vm = exec.vm();
299         Base::finishCreation(vm);
300         ASSERT(!sumOverflows<int32_t>(offset, length));
301         ASSERT(offset + length <= base.length());
302         m_length = length;
303         setIs8Bit(base.is8Bit());
304         setIsSubstring(true);
305         if (base.isSubstring()) {
306             JSRopeString& baseRope = static_cast<JSRopeString&>(base);
307             substringBase().set(vm, this, baseRope.substringBase().get());
308             substringOffset() = baseRope.substringOffset() + offset;
309         } else {
310             substringBase().set(vm, this, &base);
311             substringOffset() = offset;
312
313             // For now, let's not allow substrings with a rope base.
314             // Resolve non-substring rope bases so we don't have to deal with it.
315             // FIXME: Evaluate if this would be worth adding more branches.
316             if (base.isRope())
317                 static_cast<JSRopeString&>(base).resolveRope(&exec);
318         }
319     }
320
321     void finishCreation(VM& vm)
322     {
323         JSString::finishCreation(vm);
324         setIsSubstring(false);
325         fiber(0).clear();
326         fiber(1).clear();
327         fiber(2).clear();
328     }
329
330     void append(VM& vm, size_t index, JSString* jsString)
331     {
332         fiber(index).set(vm, this, jsString);
333         m_length += jsString->m_length;
334         RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
335         setIs8Bit(is8Bit() && jsString->is8Bit());
336     }
337
338     static JSRopeString* createNull(VM& vm)
339     {
340         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
341         newString->finishCreation(vm);
342         return newString;
343     }
344
345 public:
346     static JSString* create(VM& vm, JSString* s1, JSString* s2)
347     {
348         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
349         newString->finishCreation(vm, s1, s2);
350         return newString;
351     }
352     static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
353     {
354         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
355         newString->finishCreation(vm, s1, s2, s3);
356         return newString;
357     }
358
359     static JSString* create(ExecState& exec, JSString& base, unsigned offset, unsigned length)
360     {
361         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(exec.vm().heap)) JSRopeString(exec.vm());
362         newString->finishCreation(exec, base, offset, length);
363         return newString;
364     }
365
366     void visitFibers(SlotVisitor&);
367
368     static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, u); }
369
370     static const unsigned s_maxInternalRopeLength = 3;
371
372 private:
373     friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned);
374     friend JSValue jsStringFromArguments(ExecState*, JSValue);
375
376     JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
377     JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const;
378     JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const;
379     void resolveRopeSlowCase8(LChar*) const;
380     void resolveRopeSlowCase(UChar*) const;
381     void outOfMemory(ExecState*) const;
382     void resolveRopeInternal8(LChar*) const;
383     void resolveRopeInternal8NoSubstring(LChar*) const;
384     void resolveRopeInternal16(UChar*) const;
385     void resolveRopeInternal16NoSubstring(UChar*) const;
386     void clearFibers() const;
387     StringView unsafeView(ExecState&) const;
388     StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const;
389
390     WriteBarrierBase<JSString>& fiber(unsigned i) const
391     {
392         ASSERT(!isSubstring());
393         ASSERT(i < s_maxInternalRopeLength);
394         return u[i].string;
395     }
396
397     WriteBarrierBase<JSString>& substringBase() const
398     {
399         return u[1].string;
400     }
401
402     uintptr_t& substringOffset() const
403     {
404         return u[2].number;
405     }
406
407     static uintptr_t notSubstringSentinel()
408     {
409         return 0;
410     }
411
412     static uintptr_t substringSentinel()
413     {
414         return 1;
415     }
416
417     bool isSubstring() const
418     {
419         return u[0].number == substringSentinel();
420     }
421
422     void setIsSubstring(bool isSubstring)
423     {
424         u[0].number = isSubstring ? substringSentinel() : notSubstringSentinel();
425     }
426
427     mutable union {
428         uintptr_t number;
429         WriteBarrierBase<JSString> string;
430     } u[s_maxInternalRopeLength];
431 };
432
433 class JSString::SafeView {
434 public:
435     explicit SafeView(ExecState&, const JSString&);
436     StringView get() const;
437
438     bool is8Bit() const { return m_string->is8Bit(); }
439     unsigned length() const { return m_string->length(); }
440     const LChar* characters8() const { return get().characters8(); }
441     const UChar* characters16() const { return get().characters16(); }
442     UChar operator[](unsigned index) const { return get()[index]; }
443
444 private:
445     ExecState& m_state;
446
447     // The following pointer is marked "volatile" to make the compiler leave it on the stack
448     // or in a register as long as this object is alive, even after the last use of the pointer.
449     // That's needed to prevent garbage collecting the string and possibly deleting the block
450     // with the characters in it, and then using the StringView after that.
451     const JSString* volatile m_string;
452 };
453
454 JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&);
455
456 inline const StringImpl* JSString::tryGetValueImpl() const
457 {
458     return m_value.impl();
459 }
460
461 inline JSString* asString(JSValue value)
462 {
463     ASSERT(value.asCell()->isString());
464     return jsCast<JSString*>(value.asCell());
465 }
466
467 inline JSString* jsEmptyString(VM* vm)
468 {
469     return vm->smallStrings.emptyString();
470 }
471
472 ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
473 {
474     if (c <= maxSingleCharacterString)
475         return vm->smallStrings.singleCharacterString(c);
476     return JSString::create(*vm, String(&c, 1).impl());
477 }
478
479 inline JSString* jsNontrivialString(VM* vm, const String& s)
480 {
481     ASSERT(s.length() > 1);
482     return JSString::create(*vm, s.impl());
483 }
484
485 inline JSString* jsNontrivialString(VM* vm, String&& s)
486 {
487     ASSERT(s.length() > 1);
488     return JSString::create(*vm, s.releaseImpl());
489 }
490
491 ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const
492 {
493     return Identifier::fromString(exec, toAtomicString(exec));
494 }
495
496 ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const
497 {
498     if (isRope())
499         static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
500     return AtomicString(m_value);
501 }
502
503 ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const
504 {
505     if (isRope())
506         return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec);
507     if (m_value.impl()->isAtomic())
508         return static_cast<AtomicStringImpl*>(m_value.impl());
509     return AtomicStringImpl::lookUp(m_value.impl());
510 }
511
512 inline const String& JSString::value(ExecState* exec) const
513 {
514     if (isRope())
515         static_cast<const JSRopeString*>(this)->resolveRope(exec);
516     return m_value;
517 }
518
519 inline const String& JSString::tryGetValue() const
520 {
521     if (isRope())
522         static_cast<const JSRopeString*>(this)->resolveRope(0);
523     return m_value;
524 }
525
526 inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
527 {
528     ASSERT(canGetIndex(i));
529     return jsSingleCharacterString(exec, unsafeView(*exec)[i]);
530 }
531
532 inline JSString* jsString(VM* vm, const String& s)
533 {
534     int size = s.length();
535     if (!size)
536         return vm->smallStrings.emptyString();
537     if (size == 1) {
538         UChar c = s.characterAt(0);
539         if (c <= maxSingleCharacterString)
540             return vm->smallStrings.singleCharacterString(c);
541     }
542     return JSString::create(*vm, s.impl());
543 }
544
545 inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
546 {
547     ASSERT(offset <= static_cast<unsigned>(s->length()));
548     ASSERT(length <= static_cast<unsigned>(s->length()));
549     ASSERT(offset + length <= static_cast<unsigned>(s->length()));
550     VM& vm = exec->vm();
551     if (!length)
552         return vm.smallStrings.emptyString();
553     if (!offset && length == s->length())
554         return s;
555     return JSRopeString::create(*exec, *s, offset, length);
556 }
557
558 inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length)
559 {
560     ASSERT(offset <= static_cast<unsigned>(s.length()));
561     ASSERT(length <= static_cast<unsigned>(s.length()));
562     ASSERT(offset + length <= static_cast<unsigned>(s.length()));
563     if (!length)
564         return vm->smallStrings.emptyString();
565     if (length == 1) {
566         UChar c = s.characterAt(offset);
567         if (c <= maxSingleCharacterString)
568             return vm->smallStrings.singleCharacterString(c);
569     }
570     return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl8(s.impl(), offset, length));
571 }
572
573 inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
574 {
575     ASSERT(offset <= static_cast<unsigned>(s.length()));
576     ASSERT(length <= static_cast<unsigned>(s.length()));
577     ASSERT(offset + length <= static_cast<unsigned>(s.length()));
578     if (!length)
579         return vm->smallStrings.emptyString();
580     if (length == 1) {
581         UChar c = s.characterAt(offset);
582         if (c <= maxSingleCharacterString)
583             return vm->smallStrings.singleCharacterString(c);
584     }
585     return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, length));
586 }
587
588 inline JSString* jsOwnedString(VM* vm, const String& s)
589 {
590     int size = s.length();
591     if (!size)
592         return vm->smallStrings.emptyString();
593     if (size == 1) {
594         UChar c = s.characterAt(0);
595         if (c <= maxSingleCharacterString)
596             return vm->smallStrings.singleCharacterString(c);
597     }
598     return JSString::createHasOtherOwner(*vm, s.impl());
599 }
600
601 inline JSRopeString* jsStringBuilder(VM* vm)
602 {
603     return JSRopeString::createNull(*vm);
604 }
605
606 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
607 inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
608 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
609 inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); }
610 inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
611 inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
612 inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTFMove(s)); }
613 inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
614
615 ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s)
616 {
617     VM& vm = exec->vm();
618     StringImpl* stringImpl = s.impl();
619     if (!stringImpl || !stringImpl->length())
620         return jsEmptyString(&vm);
621
622     if (stringImpl->length() == 1) {
623         UChar singleCharacter = (*stringImpl)[0u];
624         if (singleCharacter <= maxSingleCharacterString)
625             return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
626     }
627
628     if (JSString* lastCachedString = vm.lastCachedString.get()) {
629         if (lastCachedString->tryGetValueImpl() == stringImpl)
630             return lastCachedString;
631     }
632
633     return jsStringWithCacheSlowCase(vm, *stringImpl);
634 }
635
636 ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const AtomicString& s)
637 {
638     return jsStringWithCache(exec, s.string());
639 }
640
641 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
642 {
643     if (propertyName == exec->propertyNames().length) {
644         slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length));
645         return true;
646     }
647
648     Optional<uint32_t> index = parseIndex(propertyName);
649     if (index && index.value() < m_length) {
650         slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, index.value()));
651         return true;
652     }
653
654     return false;
655 }
656
657 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
658 {
659     if (propertyName < m_length) {
660         slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName));
661         return true;
662     }
663
664     return false;
665 }
666
667 inline bool isJSString(JSValue v)
668 {
669     return v.isCell() && v.asCell()->type() == StringType;
670 }
671
672 ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState& state) const
673 {
674     if (isSubstring()) {
675         if (is8Bit())
676             return StringView(substringBase()->m_value.characters8() + substringOffset(), m_length);
677         return StringView(substringBase()->m_value.characters16() + substringOffset(), m_length);
678     }
679     resolveRope(&state);
680     return m_value;
681 }
682
683 ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState& state) const
684 {
685     if (isSubstring()) {
686         auto& base = substringBase()->m_value;
687         if (is8Bit())
688             return { { base.characters8() + substringOffset(), m_length }, base };
689         return { { base.characters16() + substringOffset(), m_length }, base };
690     }
691     resolveRope(&state);
692     return { m_value, m_value };
693 }
694
695 ALWAYS_INLINE StringView JSString::unsafeView(ExecState& state) const
696 {
697     if (isRope())
698         return static_cast<const JSRopeString*>(this)->unsafeView(state);
699     return m_value;
700 }
701
702 ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState& state) const
703 {
704     if (isRope())
705         return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(state);
706     return { m_value, m_value };
707 }
708
709 inline bool JSString::isSubstring() const
710 {
711     return isRope() && static_cast<const JSRopeString*>(this)->isSubstring();
712 }
713
714 inline JSString::SafeView::SafeView(ExecState& state, const JSString& string)
715     : m_state(state)
716     , m_string(&string)
717 {
718 }
719
720 inline StringView JSString::SafeView::get() const
721 {
722     return m_string->unsafeView(m_state);
723 }
724
725 ALWAYS_INLINE JSString::SafeView JSString::view(ExecState* exec) const
726 {
727     return SafeView(*exec, *this);
728 }
729
730 // --- JSValue inlines ----------------------------
731
732 inline bool JSValue::toBoolean(ExecState* exec) const
733 {
734     if (isInt32())
735         return asInt32();
736     if (isDouble())
737         return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
738     if (isCell())
739         return asCell()->toBoolean(exec);
740     return isTrue(); // false, null, and undefined all convert to false.
741 }
742
743 inline JSString* JSValue::toString(ExecState* exec) const
744 {
745     if (isString())
746         return jsCast<JSString*>(asCell());
747     return toStringSlowCase(exec);
748 }
749
750 inline String JSValue::toWTFString(ExecState* exec) const
751 {
752     if (isString())
753         return static_cast<JSString*>(asCell())->value(exec);
754     return toWTFStringSlowCase(exec);
755 }
756
757 } // namespace JSC
758
759 #endif // JSString_h