6fc54679e27e63d4d31bf86e98a40d89ecf9bc9e
[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-2019 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 #pragma once
24
25 #include "ArgList.h"
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 "ThrowScope.h"
33 #include <array>
34 #include <wtf/CheckedArithmetic.h>
35 #include <wtf/ForbidHeapAllocation.h>
36 #include <wtf/text/StringView.h>
37
38 namespace JSC {
39
40 class JSString;
41 class JSRopeString;
42 class LLIntOffsetsExtractor;
43
44 JSString* jsEmptyString(VM*);
45 JSString* jsEmptyString(ExecState*);
46 JSString* jsString(VM*, const String&); // returns empty string if passed null string
47 JSString* jsString(ExecState*, const String&); // returns empty string if passed null string
48
49 JSString* jsSingleCharacterString(VM*, UChar);
50 JSString* jsSingleCharacterString(ExecState*, UChar);
51 JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
52 JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
53
54 // Non-trivial strings are two or more characters long.
55 // These functions are faster than just calling jsString.
56 JSString* jsNontrivialString(VM*, const String&);
57 JSString* jsNontrivialString(ExecState*, const String&);
58 JSString* jsNontrivialString(ExecState*, String&&);
59
60 // Should be used for strings that are owned by an object that will
61 // likely outlive the JSValue this makes, such as the parse tree or a
62 // DOM object that contains a String
63 JSString* jsOwnedString(VM*, const String&);
64 JSString* jsOwnedString(ExecState*, const String&);
65
66 bool isJSString(JSCell*);
67 bool isJSString(JSValue);
68 JSString* asString(JSValue);
69
70 struct StringViewWithUnderlyingString {
71     StringView view;
72     String underlyingString;
73 };
74
75
76 // In 64bit architecture, JSString and JSRopeString have the following memory layout to make sizeof(JSString) == 16 and sizeof(JSRopeString) == 32.
77 // JSString has only one pointer. We use it for String. length() and is8Bit() queries go to StringImpl. In JSRopeString, we reuse the above pointer
78 // place for the 1st fiber. JSRopeString has three fibers so its size is 48. To keep length and is8Bit flag information in JSRopeString, JSRopeString
79 // encodes these information into the fiber pointers. is8Bit flag is encoded in the 1st fiber pointer. length is embedded directly, and two fibers
80 // are compressed into 12bytes. isRope information is encoded in the first fiber's LSB.
81 //
82 // Since length of JSRopeString should be frequently accessed compared to each fiber, we put length in contiguous 32byte field, and compress 2nd
83 // and 3rd fibers into the following 80byte fields. One problem is that now 2nd and 3rd fibers are split. Storing and loading 2nd and 3rd fibers
84 // are not one pointer load operation. To make concurrent collector work correctly, we must initialize 2nd and 3rd fibers at JSRopeString creation
85 // and we must not modify these part later.
86 //
87 //              0                        8        10               16                       32                                     48
88 // JSString     [   ID      ][  header  ][   String pointer      0]
89 // JSRopeString [   ID      ][  header  ][ flags ][ 1st fiber    1][  length  ][2nd lower32][2nd upper16][3rd lower16][3rd upper32]
90 //                                                               ^
91 //                                                            isRope bit
92 class JSString : public JSCell {
93 public:
94     friend class JIT;
95     friend class VM;
96     friend class SpecializedThunkJIT;
97     friend class JSRopeString;
98     friend class MarkStack;
99     friend class SlotVisitor;
100     friend class SmallStrings;
101
102     typedef JSCell Base;
103     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal | OverridesToThis;
104
105     static const bool needsDestruction = true;
106     static void destroy(JSCell*);
107     
108     // We specialize the string subspace to get the fastest possible sweep. This wouldn't be
109     // necessary if JSString didn't have a destructor.
110     template<typename, SubspaceAccess>
111     static CompleteSubspace* subspaceFor(VM& vm)
112     {
113         return &vm.stringSpace;
114     }
115     
116     // We employ overflow checks in many places with the assumption that MaxLength
117     // is INT_MAX. Hence, it cannot be changed into another length value without
118     // breaking all the bounds and overflow checks that assume this.
119     static constexpr unsigned MaxLength = std::numeric_limits<int32_t>::max();
120     static_assert(MaxLength == String::MaxLength, "");
121
122     static constexpr uintptr_t isRopeInPointer = 0x1;
123
124 private:
125     String& uninitializedValueInternal() const
126     {
127         return *bitwise_cast<String*>(&m_fiber);
128     }
129
130     String& valueInternal() const
131     {
132         ASSERT(!isRope());
133         return uninitializedValueInternal();
134     }
135
136     JSString(VM& vm, Ref<StringImpl>&& value)
137         : JSCell(vm, vm.stringStructure.get())
138     {
139         new (&uninitializedValueInternal()) String(WTFMove(value));
140     }
141
142     JSString(VM& vm)
143         : JSCell(vm, vm.stringStructure.get())
144         , m_fiber(isRopeInPointer)
145     {
146     }
147
148     void finishCreation(VM& vm, unsigned length)
149     {
150         ASSERT_UNUSED(length, length > 0);
151         ASSERT(!valueInternal().isNull());
152         Base::finishCreation(vm);
153     }
154
155     void finishCreation(VM& vm, unsigned length, size_t cost)
156     {
157         ASSERT_UNUSED(length, length > 0);
158         ASSERT(!valueInternal().isNull());
159         Base::finishCreation(vm);
160         vm.heap.reportExtraMemoryAllocated(cost);
161     }
162
163     static JSString* createEmptyString(VM&);
164
165     static JSString* create(VM& vm, Ref<StringImpl>&& value)
166     {
167         unsigned length = value->length();
168         ASSERT(length > 0);
169         size_t cost = value->cost();
170         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, WTFMove(value));
171         newString->finishCreation(vm, length, cost);
172         return newString;
173     }
174     static JSString* createHasOtherOwner(VM& vm, Ref<StringImpl>&& value)
175     {
176         unsigned length = value->length();
177         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, WTFMove(value));
178         newString->finishCreation(vm, length);
179         return newString;
180     }
181
182 protected:
183     void finishCreation(VM& vm)
184     {
185         Base::finishCreation(vm);
186     }
187
188 public:
189     ~JSString();
190
191     Identifier toIdentifier(ExecState*) const;
192     AtomicString toAtomicString(ExecState*) const;
193     RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const;
194
195     StringViewWithUnderlyingString viewWithUnderlyingString(ExecState*) const;
196
197     inline bool equal(ExecState*, JSString* other) const;
198     const String& value(ExecState*) const;
199     inline const String& tryGetValue(bool allocationAllowed = true) const;
200     const StringImpl* tryGetValueImpl() const;
201     ALWAYS_INLINE unsigned length() const;
202
203     JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
204     bool toBoolean() const { return !!length(); }
205     bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
206     JSObject* toObject(ExecState*, JSGlobalObject*) const;
207     double toNumber(ExecState*) const;
208
209     bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&);
210     bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
211     bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
212
213     bool canGetIndex(unsigned i) { return i < length(); }
214     JSString* getIndex(ExecState*, unsigned);
215
216     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
217
218     static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_fiber); }
219
220     DECLARE_EXPORT_INFO;
221
222     static void dumpToStream(const JSCell*, PrintStream&);
223     static size_t estimatedSize(JSCell*, VM&);
224     static void visitChildren(JSCell*, SlotVisitor&);
225
226     ALWAYS_INLINE bool isRope() const
227     {
228         return m_fiber & isRopeInPointer;
229     }
230
231     bool is8Bit() const;
232
233 protected:
234     friend class JSValue;
235
236     JS_EXPORT_PRIVATE bool equalSlowCase(ExecState*, JSString* other) const;
237     bool isSubstring() const;
238
239     mutable uintptr_t m_fiber;
240
241 private:
242     friend class LLIntOffsetsExtractor;
243
244     static JSValue toThis(JSCell*, ExecState*, ECMAMode);
245
246     StringView unsafeView(ExecState*) const;
247
248     friend JSString* jsString(VM*, const String&);
249     friend JSString* jsString(ExecState*, JSString*, JSString*);
250     friend JSString* jsString(ExecState*, const String&, JSString*);
251     friend JSString* jsString(ExecState*, JSString*, const String&);
252     friend JSString* jsString(ExecState*, const String&, const String&);
253     friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*);
254     friend JSString* jsString(ExecState*, const String&, const String&, const String&);
255     friend JSString* jsSingleCharacterString(VM*, UChar);
256     friend JSString* jsNontrivialString(VM*, const String&);
257     friend JSString* jsNontrivialString(VM*, String&&);
258     friend JSString* jsSubstring(VM*, const String&, unsigned, unsigned);
259     friend JSString* jsSubstring(VM&, ExecState*, JSString*, unsigned, unsigned);
260     friend JSString* jsSubstringOfResolved(VM&, GCDeferralContext*, JSString*, unsigned, unsigned);
261     friend JSString* jsOwnedString(VM*, const String&);
262 };
263
264 // NOTE: This class cannot override JSString's destructor. JSString's destructor is called directly
265 // from JSStringSubspace::
266 class JSRopeString final : public JSString {
267     friend class JSString;
268 public:
269 #if CPU(ADDRESS64)
270     static_assert(sizeof(uintptr_t) == sizeof(uint64_t), "");
271     static constexpr uintptr_t flagMask = 0xffff000000000000ULL;
272     static constexpr uintptr_t stringMask = ~(flagMask | isRopeInPointer);
273     static_assert(StringImpl::flagIs8Bit() == 0b100, "");
274     static constexpr uintptr_t is8BitInPointer = static_cast<uintptr_t>(StringImpl::flagIs8Bit()) << 48;
275
276     class CompactFibers {
277     public:
278         JSString* fiber1() const
279         {
280             return bitwise_cast<JSString*>(static_cast<uintptr_t>(m_fiber1Lower) | (static_cast<uintptr_t>(m_fiber1Upper) << 32));
281         }
282
283         void initializeFiber1(JSString* fiber)
284         {
285             uintptr_t pointer = bitwise_cast<uintptr_t>(fiber);
286             m_fiber1Lower = static_cast<uint32_t>(pointer);
287             m_fiber1Upper = static_cast<uint16_t>(pointer >> 32);
288         }
289
290         JSString* fiber2() const
291         {
292             return bitwise_cast<JSString*>(static_cast<uintptr_t>(m_fiber2Lower) | (static_cast<uintptr_t>(m_fiber2Upper) << 32));
293         }
294         void initializeFiber2(JSString* fiber)
295         {
296             uintptr_t pointer = bitwise_cast<uintptr_t>(fiber);
297             m_fiber2Lower = static_cast<uint32_t>(pointer);
298             m_fiber2Upper = static_cast<uint16_t>(pointer >> 32);
299         }
300
301         unsigned length() const { return m_length; }
302         void initializeLength(unsigned length)
303         {
304             m_length = length;
305         }
306
307         static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(CompactFibers, m_length); }
308         static ptrdiff_t offsetOfFiber1Lower() { return OBJECT_OFFSETOF(CompactFibers, m_fiber1Lower); }
309         static ptrdiff_t offsetOfFiber1Upper() { return OBJECT_OFFSETOF(CompactFibers, m_fiber1Upper); }
310         static ptrdiff_t offsetOfFiber2Lower() { return OBJECT_OFFSETOF(CompactFibers, m_fiber2Lower); }
311         static ptrdiff_t offsetOfFiber2Upper() { return OBJECT_OFFSETOF(CompactFibers, m_fiber2Upper); }
312
313     private:
314         uint32_t m_length { 0 };
315         uint32_t m_fiber1Lower { 0 };
316         uint16_t m_fiber1Upper { 0 };
317         uint16_t m_fiber2Upper { 0 };
318         uint32_t m_fiber2Lower { 0 };
319     };
320     static_assert(sizeof(CompactFibers) == sizeof(void*) * 2, "");
321 #else
322     static constexpr uintptr_t stringMask = ~(isRopeInPointer);
323
324     class CompactFibers {
325     public:
326         JSString* fiber1() const
327         {
328             return m_fiber1;
329         }
330         void initializeFiber1(JSString* fiber)
331         {
332             m_fiber1 = fiber;
333         }
334
335         JSString* fiber2() const
336         {
337             return m_fiber2;
338         }
339         void initializeFiber2(JSString* fiber)
340         {
341             m_fiber2 = fiber;
342         }
343
344         unsigned length() const { return m_length; }
345         void initializeLength(unsigned length)
346         {
347             m_length = length;
348         }
349
350         void initializeIs8Bit(bool flag)
351         {
352             if (flag)
353                 m_flags |= static_cast<uintptr_t>(StringImpl::flagIs8Bit());
354             else
355                 m_flags &= ~static_cast<uintptr_t>(StringImpl::flagIs8Bit());
356         }
357
358         bool is8Bit()
359         {
360             return m_flags & static_cast<uintptr_t>(StringImpl::flagIs8Bit());
361         }
362
363         static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(CompactFibers, m_length); }
364
365     private:
366         uint32_t m_length { 0 };
367         uint32_t m_flags { 0 };
368         JSString* m_fiber1 { nullptr };
369         JSString* m_fiber2 { nullptr };
370     };
371 #endif
372
373     template <class OverflowHandler = CrashOnOverflow>
374     class RopeBuilder : public OverflowHandler {
375         WTF_FORBID_HEAP_ALLOCATION;
376     public:
377         RopeBuilder(VM& vm)
378             : m_vm(vm)
379         {
380         }
381
382         bool append(JSString* jsString)
383         {
384             if (UNLIKELY(this->hasOverflowed()))
385                 return false;
386             if (!jsString->length())
387                 return true;
388             if (m_strings.size() == JSRopeString::s_maxInternalRopeLength)
389                 expand();
390
391             static_assert(JSString::MaxLength == std::numeric_limits<int32_t>::max(), "");
392             auto sum = checkedSum<int32_t>(m_length, jsString->length());
393             if (sum.hasOverflowed()) {
394                 this->overflowed();
395                 return false;
396             }
397             ASSERT(static_cast<unsigned>(sum.unsafeGet()) <= MaxLength);
398             m_strings.append(jsString);
399             m_length = static_cast<unsigned>(sum.unsafeGet());
400             return true;
401         }
402
403         JSString* release()
404         {
405             RELEASE_ASSERT(!this->hasOverflowed());
406             JSString* result = nullptr;
407             switch (m_strings.size()) {
408             case 0: {
409                 ASSERT(!m_length);
410                 result = jsEmptyString(&m_vm);
411                 break;
412             }
413             case 1: {
414                 result = asString(m_strings.at(0));
415                 break;
416             }
417             case 2: {
418                 result = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)));
419                 break;
420             }
421             case 3: {
422                 result = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)), asString(m_strings.at(2)));
423                 break;
424             }
425             default:
426                 ASSERT_NOT_REACHED();
427                 break;
428             }
429             ASSERT(result->length() == m_length);
430             m_strings.clear();
431             m_length = 0;
432             return result;
433         }
434
435         unsigned length() const
436         {
437             ASSERT(!this->hasOverflowed());
438             return m_length;
439         }
440
441     private:
442         void expand();
443
444         VM& m_vm;
445         MarkedArgumentBuffer m_strings;
446         unsigned m_length { 0 };
447     };
448
449     inline unsigned length() const
450     {
451         return m_compactFibers.length();
452     }
453
454 private:
455     void convertToNonRope(String&&) const;
456
457     void initializeIs8Bit(bool flag) const
458     {
459 #if CPU(ADDRESS64)
460         if (flag)
461             m_fiber |= is8BitInPointer;
462         else
463             m_fiber &= ~is8BitInPointer;
464 #else
465         m_compactFibers.initializeIs8Bit(flag);
466 #endif
467     }
468
469     ALWAYS_INLINE void initializeLength(unsigned length)
470     {
471         ASSERT(length <= MaxLength);
472         m_compactFibers.initializeLength(length);
473     }
474
475     JSRopeString(VM& vm, JSString* s1, JSString* s2)
476         : JSString(vm)
477     {
478         ASSERT(!sumOverflows<int32_t>(s1->length(), s2->length()));
479         initializeIsSubstring(false);
480         initializeLength(s1->length() + s2->length());
481         initializeIs8Bit(s1->is8Bit() && s2->is8Bit());
482         initializeFiber0(s1);
483         initializeFiber1(s2);
484         initializeFiber2(nullptr);
485         ASSERT((s1->length() + s2->length()) == length());
486     }
487
488     JSRopeString(VM& vm, JSString* s1, JSString* s2, JSString* s3)
489         : JSString(vm)
490     {
491         ASSERT(!sumOverflows<int32_t>(s1->length(), s2->length(), s3->length()));
492         initializeIsSubstring(false);
493         initializeLength(s1->length() + s2->length() + s3->length());
494         initializeIs8Bit(s1->is8Bit() && s2->is8Bit() &&  s3->is8Bit());
495         initializeFiber0(s1);
496         initializeFiber1(s2);
497         initializeFiber2(s3);
498         ASSERT((s1->length() + s2->length() + s3->length()) == length());
499     }
500
501     JSRopeString(VM& vm, JSString* base, unsigned offset, unsigned length)
502         : JSString(vm)
503     {
504         RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length));
505         RELEASE_ASSERT(offset + length <= base->length());
506         initializeIsSubstring(true);
507         initializeLength(length);
508         initializeIs8Bit(base->is8Bit());
509         if (base->isSubstring()) {
510             JSRopeString* baseRope = jsCast<JSRopeString*>(base);
511             initializeSubstringBase(baseRope->substringBase());
512             initializeSubstringOffset(baseRope->substringOffset() + offset);
513         } else {
514             initializeSubstringBase(base);
515             initializeSubstringOffset(offset);
516         }
517         ASSERT(length == this->length());
518     }
519
520     enum SubstringOfResolvedTag { SubstringOfResolved };
521     JSRopeString(SubstringOfResolvedTag, VM& vm, JSString* base, unsigned offset, unsigned length)
522         : JSString(vm)
523     {
524         RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length));
525         RELEASE_ASSERT(offset + length <= base->length());
526         initializeIsSubstring(true);
527         initializeLength(length);
528         initializeIs8Bit(base->is8Bit());
529         initializeSubstringBase(base);
530         initializeSubstringOffset(offset);
531         ASSERT(length == this->length());
532     }
533
534     ALWAYS_INLINE void finishCreationSubstring(VM& vm, ExecState* exec)
535     {
536         Base::finishCreation(vm);
537         JSString* updatedBase = substringBase();
538         // For now, let's not allow substrings with a rope base.
539         // Resolve non-substring rope bases so we don't have to deal with it.
540         // FIXME: Evaluate if this would be worth adding more branches.
541         if (updatedBase->isRope())
542             jsCast<JSRopeString*>(updatedBase)->resolveRope(exec);
543     }
544
545     ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm)
546     {
547         Base::finishCreation(vm);
548     }
549
550 public:
551     static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfLength(); } // 32byte width.
552     static ptrdiff_t offsetOfFiber0() { return offsetOfValue(); }
553 #if CPU(ADDRESS64)
554     static ptrdiff_t offsetOfFlags() { return offsetOfValue() + sizeof(uint16_t) * 3; } // 16byte width.
555     static ptrdiff_t offsetOfFiber1Lower() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber1Lower(); } // 32byte width.
556     static ptrdiff_t offsetOfFiber1Upper() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber1Upper(); } // 16byte width.
557     static ptrdiff_t offsetOfFiber2Lower() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber2Lower(); } // 32byte width.
558     static ptrdiff_t offsetOfFiber2Upper() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber2Upper(); } // 16byte width.
559 #elif USE(JSVALUE64)
560     // FIXME: This is an temporary workaround to make JSC built on ARM64_32. Once we start calculating bits before storing them to JSRopeString,
561     // we do not need to have such a detailed information as an offset. After that, what we only need is offsetOfFiber0, offsetOfFiber1, and offsetOfFiber2.
562     // https://bugs.webkit.org/show_bug.cgi?id=195234
563     static ptrdiff_t offsetOfFlags() { ASSERT_NOT_REACHED(); return 0; }
564     static ptrdiff_t offsetOfFiber1Lower() { ASSERT_NOT_REACHED(); return 0; }
565     static ptrdiff_t offsetOfFiber1Upper() { ASSERT_NOT_REACHED(); return 0; }
566     static ptrdiff_t offsetOfFiber2Lower() { ASSERT_NOT_REACHED(); return 0; }
567     static ptrdiff_t offsetOfFiber2Upper() { ASSERT_NOT_REACHED(); return 0; }
568 #endif
569
570     static constexpr unsigned s_maxInternalRopeLength = 3;
571
572 private:
573     static JSRopeString* create(VM& vm, JSString* s1, JSString* s2)
574     {
575         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, s1, s2);
576         newString->finishCreation(vm);
577         ASSERT(newString->length());
578         return newString;
579     }
580     static JSRopeString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
581     {
582         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, s1, s2, s3);
583         newString->finishCreation(vm);
584         ASSERT(newString->length());
585         return newString;
586     }
587
588     static JSRopeString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
589     {
590         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, base, offset, length);
591         newString->finishCreationSubstring(vm, exec);
592         ASSERT(newString->length());
593         return newString;
594     }
595
596     ALWAYS_INLINE static JSRopeString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length)
597     {
598         JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(SubstringOfResolved, vm, base, offset, length);
599         newString->finishCreationSubstringOfResolved(vm);
600         ASSERT(newString->length());
601         return newString;
602     }
603
604     friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned);
605     friend JSValue jsStringFromArguments(ExecState*, JSValue);
606
607     // If nullOrExecForOOM is null, resolveRope() will be do nothing in the event of an OOM error.
608     // The rope value will remain a null string in that case.
609     JS_EXPORT_PRIVATE const String& resolveRope(ExecState* nullOrExecForOOM) const;
610     template<typename Function> const String& resolveRopeWithFunction(ExecState* nullOrExecForOOM, Function&&) const;
611     JS_EXPORT_PRIVATE AtomicString resolveRopeToAtomicString(ExecState*) const;
612     JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const;
613     void resolveRopeSlowCase8(LChar*) const;
614     void resolveRopeSlowCase(UChar*) const;
615     void outOfMemory(ExecState* nullOrExecForOOM) const;
616     void resolveRopeInternal8(LChar*) const;
617     void resolveRopeInternal8NoSubstring(LChar*) const;
618     void resolveRopeInternal16(UChar*) const;
619     void resolveRopeInternal16NoSubstring(UChar*) const;
620     StringView unsafeView(ExecState*) const;
621     StringViewWithUnderlyingString viewWithUnderlyingString(ExecState*) const;
622
623     JSString* fiber0() const
624     {
625         return bitwise_cast<JSString*>(m_fiber & stringMask);
626     }
627
628     JSString* fiber1() const
629     {
630         return m_compactFibers.fiber1();
631     }
632
633     JSString* fiber2() const
634     {
635         return m_compactFibers.fiber2();
636     }
637
638     JSString* fiber(unsigned i) const
639     {
640         ASSERT(!isSubstring());
641         ASSERT(i < s_maxInternalRopeLength);
642         switch (i) {
643         case 0:
644             return fiber0();
645         case 1:
646             return fiber1();
647         case 2:
648             return fiber2();
649         }
650         ASSERT_NOT_REACHED();
651         return nullptr;
652     }
653
654     void initializeFiber0(JSString* fiber)
655     {
656         uintptr_t pointer = bitwise_cast<uintptr_t>(fiber);
657         ASSERT(!(pointer & ~stringMask));
658         m_fiber = (pointer | (m_fiber & ~stringMask));
659     }
660
661     void initializeFiber1(JSString* fiber)
662     {
663         m_compactFibers.initializeFiber1(fiber);
664     }
665
666     void initializeFiber2(JSString* fiber)
667     {
668         m_compactFibers.initializeFiber2(fiber);
669     }
670
671     void initializeSubstringBase(JSString* fiber)
672     {
673         initializeFiber1(fiber);
674     }
675
676     JSString* substringBase() const { return fiber1(); }
677
678     void initializeSubstringOffset(unsigned offset)
679     {
680         m_compactFibers.initializeFiber2(bitwise_cast<JSString*>(static_cast<uintptr_t>(offset)));
681     }
682
683     unsigned substringOffset() const
684     {
685         return static_cast<unsigned>(bitwise_cast<uintptr_t>(fiber2()));
686     }
687
688     static constexpr uintptr_t notSubstringSentinel()
689     {
690         return 0;
691     }
692
693     static constexpr uintptr_t substringSentinel()
694     {
695         return 2;
696     }
697
698     bool isSubstring() const
699     {
700         return (m_fiber & stringMask) == substringSentinel();
701     }
702
703     void initializeIsSubstring(bool isSubstring)
704     {
705         m_fiber |= (isSubstring ? substringSentinel() : notSubstringSentinel());
706     }
707
708     static_assert(s_maxInternalRopeLength >= 2, "");
709     mutable CompactFibers m_compactFibers;
710
711     friend JSString* jsString(ExecState*, JSString*, JSString*);
712     friend JSString* jsString(ExecState*, const String&, JSString*);
713     friend JSString* jsString(ExecState*, JSString*, const String&);
714     friend JSString* jsString(ExecState*, const String&, const String&);
715     friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*);
716     friend JSString* jsString(ExecState*, const String&, const String&, const String&);
717     friend JSString* jsSubstringOfResolved(VM&, GCDeferralContext*, JSString*, unsigned, unsigned);
718     friend JSString* jsSubstring(VM&, ExecState*, JSString*, unsigned, unsigned);
719 };
720
721 JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&);
722
723 // JSString::is8Bit is safe to be called concurrently. Concurrent threads can access is8Bit even if the main thread
724 // is in the middle of converting JSRopeString to JSString.
725 ALWAYS_INLINE bool JSString::is8Bit() const
726 {
727     uintptr_t pointer = m_fiber;
728     if (pointer & isRopeInPointer) {
729 #if CPU(ADDRESS64)
730         // Do not load m_fiber twice. We should use the information in pointer.
731         // Otherwise, JSRopeString may be converted to JSString between the first and second accesses.
732         return pointer & JSRopeString::is8BitInPointer;
733 #else
734         // It is OK to load flag since even if JSRopeString is converted to JSString, this flag still exists.
735         return jsCast<const JSRopeString*>(this)->m_compactFibers.is8Bit();
736 #endif
737     }
738     return bitwise_cast<StringImpl*>(pointer)->is8Bit();
739 }
740
741 // JSString::length is safe to be called concurrently. Concurrent threads can access length even if the main thread
742 // is in the middle of converting JSRopeString to JSString. This is OK because we never override the length bits
743 // when we resolve a JSRopeString.
744 ALWAYS_INLINE unsigned JSString::length() const
745 {
746     uintptr_t pointer = m_fiber;
747     if (pointer & isRopeInPointer)
748         return jsCast<const JSRopeString*>(this)->length();
749     return bitwise_cast<StringImpl*>(pointer)->length();
750 }
751
752 inline const StringImpl* JSString::tryGetValueImpl() const
753 {
754     uintptr_t pointer = m_fiber;
755     if (pointer & isRopeInPointer)
756         return nullptr;
757     return bitwise_cast<StringImpl*>(pointer);
758 }
759
760 inline JSString* asString(JSValue value)
761 {
762     ASSERT(value.asCell()->isString());
763     return jsCast<JSString*>(value.asCell());
764 }
765
766 // This MUST NOT GC.
767 inline JSString* jsEmptyString(VM* vm)
768 {
769     return vm->smallStrings.emptyString();
770 }
771
772 ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
773 {
774     if (validateDFGDoesGC)
775         RELEASE_ASSERT(vm->heap.expectDoesGC());
776     if (c <= maxSingleCharacterString)
777         return vm->smallStrings.singleCharacterString(c);
778     return JSString::create(*vm, StringImpl::create(&c, 1));
779 }
780
781 inline JSString* jsNontrivialString(VM* vm, const String& s)
782 {
783     ASSERT(s.length() > 1);
784     return JSString::create(*vm, *s.impl());
785 }
786
787 inline JSString* jsNontrivialString(VM* vm, String&& s)
788 {
789     ASSERT(s.length() > 1);
790     return JSString::create(*vm, s.releaseImpl().releaseNonNull());
791 }
792
793 ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const
794 {
795     return Identifier::fromString(exec, toAtomicString(exec));
796 }
797
798 ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const
799 {
800     if (validateDFGDoesGC)
801         RELEASE_ASSERT(vm()->heap.expectDoesGC());
802     if (isRope())
803         return static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
804     return AtomicString(valueInternal());
805 }
806
807 ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const
808 {
809     if (validateDFGDoesGC)
810         RELEASE_ASSERT(vm()->heap.expectDoesGC());
811     if (isRope())
812         return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec);
813     if (valueInternal().impl()->isAtomic())
814         return static_cast<AtomicStringImpl*>(valueInternal().impl());
815     return AtomicStringImpl::lookUp(valueInternal().impl());
816 }
817
818 inline const String& JSString::value(ExecState* exec) const
819 {
820     if (validateDFGDoesGC)
821         RELEASE_ASSERT(vm()->heap.expectDoesGC());
822     if (isRope())
823         return static_cast<const JSRopeString*>(this)->resolveRope(exec);
824     return valueInternal();
825 }
826
827 inline const String& JSString::tryGetValue(bool allocationAllowed) const
828 {
829     if (allocationAllowed) {
830         if (validateDFGDoesGC)
831             RELEASE_ASSERT(vm()->heap.expectDoesGC());
832         if (isRope()) {
833             // Pass nullptr for the ExecState so that resolveRope does not throw in the event of an OOM error.
834             return static_cast<const JSRopeString*>(this)->resolveRope(nullptr);
835         }
836     } else
837         RELEASE_ASSERT(!isRope());
838     return valueInternal();
839 }
840
841 inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
842 {
843     VM& vm = exec->vm();
844     auto scope = DECLARE_THROW_SCOPE(vm);
845     ASSERT(canGetIndex(i));
846     StringView view = unsafeView(exec);
847     RETURN_IF_EXCEPTION(scope, nullptr);
848     return jsSingleCharacterString(exec, view[i]);
849 }
850
851 inline JSString* jsString(VM* vm, const String& s)
852 {
853     int size = s.length();
854     if (!size)
855         return vm->smallStrings.emptyString();
856     if (size == 1) {
857         UChar c = s.characterAt(0);
858         if (c <= maxSingleCharacterString)
859             return vm->smallStrings.singleCharacterString(c);
860     }
861     return JSString::create(*vm, *s.impl());
862 }
863
864 inline JSString* jsSubstring(VM& vm, ExecState* exec, JSString* s, unsigned offset, unsigned length)
865 {
866     ASSERT(offset <= s->length());
867     ASSERT(length <= s->length());
868     ASSERT(offset + length <= s->length());
869     if (!length)
870         return vm.smallStrings.emptyString();
871     if (!offset && length == s->length())
872         return s;
873     return JSRopeString::create(vm, exec, s, offset, length);
874 }
875
876 inline JSString* jsSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* s, unsigned offset, unsigned length)
877 {
878     ASSERT(offset <= s->length());
879     ASSERT(length <= s->length());
880     ASSERT(offset + length <= s->length());
881     if (!length)
882         return vm.smallStrings.emptyString();
883     if (!offset && length == s->length())
884         return s;
885     return JSRopeString::createSubstringOfResolved(vm, deferralContext, s, offset, length);
886 }
887
888 inline JSString* jsSubstringOfResolved(VM& vm, JSString* s, unsigned offset, unsigned length)
889 {
890     return jsSubstringOfResolved(vm, nullptr, s, offset, length);
891 }
892
893 inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
894 {
895     return jsSubstring(exec->vm(), exec, s, offset, length);
896 }
897
898 inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
899 {
900     ASSERT(offset <= s.length());
901     ASSERT(length <= s.length());
902     ASSERT(offset + length <= s.length());
903     if (!length)
904         return vm->smallStrings.emptyString();
905     if (length == 1) {
906         UChar c = s.characterAt(offset);
907         if (c <= maxSingleCharacterString)
908             return vm->smallStrings.singleCharacterString(c);
909     }
910     auto impl = StringImpl::createSubstringSharingImpl(*s.impl(), offset, length);
911     if (impl->isSubString())
912         return JSString::createHasOtherOwner(*vm, WTFMove(impl));
913     return JSString::create(*vm, WTFMove(impl));
914 }
915
916 inline JSString* jsOwnedString(VM* vm, const String& s)
917 {
918     int size = s.length();
919     if (!size)
920         return vm->smallStrings.emptyString();
921     if (size == 1) {
922         UChar c = s.characterAt(0);
923         if (c <= maxSingleCharacterString)
924             return vm->smallStrings.singleCharacterString(c);
925     }
926     return JSString::createHasOtherOwner(*vm, *s.impl());
927 }
928
929 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
930 inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
931 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
932 inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
933 inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
934 inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTFMove(s)); }
935 inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
936
937 ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s)
938 {
939     VM& vm = exec->vm();
940     StringImpl* stringImpl = s.impl();
941     if (!stringImpl || !stringImpl->length())
942         return jsEmptyString(&vm);
943
944     if (stringImpl->length() == 1) {
945         UChar singleCharacter = (*stringImpl)[0u];
946         if (singleCharacter <= maxSingleCharacterString)
947             return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
948     }
949
950     if (JSString* lastCachedString = vm.lastCachedString.get()) {
951         if (lastCachedString->tryGetValueImpl() == stringImpl)
952             return lastCachedString;
953     }
954
955     return jsStringWithCacheSlowCase(vm, *stringImpl);
956 }
957
958 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
959 {
960     VM& vm = exec->vm();
961     auto scope = DECLARE_THROW_SCOPE(vm);
962
963     if (propertyName == vm.propertyNames->length) {
964         slot.setValue(this, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly, jsNumber(length()));
965         return true;
966     }
967
968     Optional<uint32_t> index = parseIndex(propertyName);
969     if (index && index.value() < length()) {
970         JSValue value = getIndex(exec, index.value());
971         RETURN_IF_EXCEPTION(scope, false);
972         slot.setValue(this, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly, value);
973         return true;
974     }
975
976     return false;
977 }
978
979 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
980 {
981     VM& vm = exec->vm();
982     auto scope = DECLARE_THROW_SCOPE(vm);
983
984     if (propertyName < length()) {
985         JSValue value = getIndex(exec, propertyName);
986         RETURN_IF_EXCEPTION(scope, false);
987         slot.setValue(this, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly, value);
988         return true;
989     }
990
991     return false;
992 }
993
994 inline bool isJSString(JSCell* cell)
995 {
996     return cell->type() == StringType;
997 }
998
999 inline bool isJSString(JSValue v)
1000 {
1001     return v.isCell() && isJSString(v.asCell());
1002 }
1003
1004 ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState* exec) const
1005 {
1006     if (validateDFGDoesGC)
1007         RELEASE_ASSERT(vm()->heap.expectDoesGC());
1008     if (isSubstring()) {
1009         auto& base = substringBase()->valueInternal();
1010         if (base.is8Bit())
1011             return StringView(base.characters8() + substringOffset(), length());
1012         return StringView(base.characters16() + substringOffset(), length());
1013     }
1014     return resolveRope(exec);
1015 }
1016
1017 ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState* exec) const
1018 {
1019     if (validateDFGDoesGC)
1020         RELEASE_ASSERT(vm()->heap.expectDoesGC());
1021     if (isSubstring()) {
1022         auto& base = substringBase()->valueInternal();
1023         if (base.is8Bit())
1024             return { { base.characters8() + substringOffset(), length() }, base };
1025         return { { base.characters16() + substringOffset(), length() }, base };
1026     }
1027     auto& string = resolveRope(exec);
1028     return { string, string };
1029 }
1030
1031 ALWAYS_INLINE StringView JSString::unsafeView(ExecState* exec) const
1032 {
1033     if (validateDFGDoesGC)
1034         RELEASE_ASSERT(vm()->heap.expectDoesGC());
1035     if (isRope())
1036         return static_cast<const JSRopeString*>(this)->unsafeView(exec);
1037     return valueInternal();
1038 }
1039
1040 ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState* exec) const
1041 {
1042     if (isRope())
1043         return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(exec);
1044     return { valueInternal(), valueInternal() };
1045 }
1046
1047 inline bool JSString::isSubstring() const
1048 {
1049     return isRope() && static_cast<const JSRopeString*>(this)->isSubstring();
1050 }
1051
1052 // --- JSValue inlines ----------------------------
1053
1054 inline bool JSValue::toBoolean(ExecState* exec) const
1055 {
1056     if (isInt32())
1057         return asInt32();
1058     if (isDouble())
1059         return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
1060     if (isCell())
1061         return asCell()->toBoolean(exec);
1062     return isTrue(); // false, null, and undefined all convert to false.
1063 }
1064
1065 inline JSString* JSValue::toString(ExecState* exec) const
1066 {
1067     if (isString())
1068         return asString(asCell());
1069     bool returnEmptyStringOnError = true;
1070     return toStringSlowCase(exec, returnEmptyStringOnError);
1071 }
1072
1073 inline JSString* JSValue::toStringOrNull(ExecState* exec) const
1074 {
1075     if (isString())
1076         return asString(asCell());
1077     bool returnEmptyStringOnError = false;
1078     return toStringSlowCase(exec, returnEmptyStringOnError);
1079 }
1080
1081 inline String JSValue::toWTFString(ExecState* exec) const
1082 {
1083     if (isString())
1084         return static_cast<JSString*>(asCell())->value(exec);
1085     return toWTFStringSlowCase(exec);
1086 }
1087
1088 } // namespace JSC