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