blob: a67cd446a97882c37d661f0d2548f9459f8c036a [file] [log] [blame]
kocienda66a6d362001-08-24 14:24:45 +00001/*
mjs6f821c82002-03-22 00:31:57 +00002 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
fpizlo@apple.com75104a32014-04-15 23:33:11 +00004 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
kocienda66a6d362001-08-24 14:24:45 +00005 *
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
mjscdff33b2006-01-23 21:41:36 +000018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
ggaren07d4ce62005-07-14 18:27:04 +000019 * Boston, MA 02110-1301, USA.
mjs6f821c82002-03-22 00:31:57 +000020 *
kocienda66a6d362001-08-24 14:24:45 +000021 */
22
darin@apple.com5c0863d2008-06-16 04:17:44 +000023#ifndef JSString_h
24#define JSString_h
weinig@apple.combe6603a2013-12-10 01:28:05 +000025
ggaren@apple.com5169fc92008-11-17 22:11:26 +000026#include "CallFrame.h"
oliver@apple.comd04e0a02014-02-01 01:37:59 +000027#include "CommonIdentifiers.h"
cwzwarich@webkit.org858b2b62008-11-05 23:37:21 +000028#include "Identifier.h"
oliver@apple.com4b4f7852009-08-26 16:52:15 +000029#include "PropertyDescriptor.h"
weinig@apple.comefdce0f2008-06-30 20:52:03 +000030#include "PropertySlot.h"
oliver@apple.comed66e772011-04-05 01:33:58 +000031#include "Structure.h"
weinig@apple.combe6603a2013-12-10 01:28:05 +000032#include <array>
akling@apple.com7e84ac52015-05-19 17:06:23 +000033#include <wtf/text/StringView.h>
ggaren5102fa12006-02-10 06:42:01 +000034
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +000035namespace JSC {
kocienda66a6d362001-08-24 14:24:45 +000036
mark.lam@apple.com188640e2014-09-04 19:10:36 +000037class JSString;
38class JSRopeString;
39class LLIntOffsetsExtractor;
darin@apple.come7945852008-08-31 06:58:07 +000040
mark.lam@apple.com188640e2014-09-04 19:10:36 +000041JSString* jsEmptyString(VM*);
42JSString* jsEmptyString(ExecState*);
43JSString* jsString(VM*, const String&); // returns empty string if passed null string
44JSString* jsString(ExecState*, const String&); // returns empty string if passed null string
darin@apple.come7945852008-08-31 06:58:07 +000045
mark.lam@apple.com188640e2014-09-04 19:10:36 +000046JSString* jsSingleCharacterString(VM*, UChar);
47JSString* jsSingleCharacterString(ExecState*, UChar);
mark.lam@apple.com188640e2014-09-04 19:10:36 +000048JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
49JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
darin@apple.com3954c6a2015-06-27 22:53:12 +000050JSString* jsSubstring8(VM*, const String&, unsigned offset, unsigned length);
51JSString* jsSubstring8(ExecState*, const String&, unsigned offset, unsigned length);
darin@apple.come7945852008-08-31 06:58:07 +000052
mark.lam@apple.com188640e2014-09-04 19:10:36 +000053// Non-trivial strings are two or more characters long.
54// These functions are faster than just calling jsString.
55JSString* jsNontrivialString(VM*, const String&);
56JSString* jsNontrivialString(ExecState*, const String&);
andersca@apple.comc69ac4e2014-10-02 16:14:25 +000057JSString* jsNontrivialString(ExecState*, String&&);
darin@apple.come7945852008-08-31 06:58:07 +000058
mark.lam@apple.com188640e2014-09-04 19:10:36 +000059// 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
62JSString* jsOwnedString(VM*, const String&);
63JSString* jsOwnedString(ExecState*, const String&);
darin@apple.come7945852008-08-31 06:58:07 +000064
mark.lam@apple.com188640e2014-09-04 19:10:36 +000065JSRopeString* jsStringBuilder(VM*);
ggaren@apple.comfbf6d9a2011-10-19 02:54:29 +000066
darin@apple.com3954c6a2015-06-27 22:53:12 +000067bool isJSString(JSValue);
68JSString* asString(JSValue);
69
darin@apple.com6d8af842015-06-24 02:33:18 +000070struct StringViewWithUnderlyingString {
71 StringView view;
72 String underlyingString;
73};
74
mark.lam@apple.com188640e2014-09-04 19:10:36 +000075class JSString : public JSCell {
76public:
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;
msaboff@apple.com6e74e922012-04-27 23:51:17 +000084
mark.lam@apple.com188640e2014-09-04 19:10:36 +000085 typedef JSCell Base;
akling@apple.com4b9e0002015-04-13 19:12:48 +000086 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal;
msaboff@apple.com6e74e922012-04-27 23:51:17 +000087
mark.lam@apple.com188640e2014-09-04 19:10:36 +000088 static const bool needsDestruction = true;
mark.lam@apple.com188640e2014-09-04 19:10:36 +000089 static void destroy(JSCell*);
msaboff@apple.com6e74e922012-04-27 23:51:17 +000090
mark.lam@apple.com188640e2014-09-04 19:10:36 +000091private:
92 JSString(VM& vm, PassRefPtr<StringImpl> value)
93 : JSCell(vm, vm.stringStructure.get())
94 , m_flags(0)
95 , m_value(value)
darin@apple.com5a494422008-10-18 23:08:12 +000096 {
darin@apple.com5a494422008-10-18 23:08:12 +000097 }
98
mark.lam@apple.com188640e2014-09-04 19:10:36 +000099 JSString(VM& vm)
100 : JSCell(vm, vm.stringStructure.get())
101 , m_flags(0)
darin@apple.come7945852008-08-31 06:58:07 +0000102 {
fpizlo@apple.com494f2d92013-03-20 23:16:01 +0000103 }
104
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000105 void finishCreation(VM& vm, size_t length)
fpizlo@apple.com494f2d92013-03-20 23:16:01 +0000106 {
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000107 ASSERT(!m_value.isNull());
108 Base::finishCreation(vm);
109 m_length = length;
110 setIs8Bit(m_value.impl()->is8Bit());
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000111 }
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());
ggaren@apple.come2ebb8c2015-03-11 21:29:57 +0000119 Heap::heap(this)->reportExtraMemoryAllocated(cost);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000120 }
121
122protected:
123 void finishCreation(VM& vm)
124 {
125 Base::finishCreation(vm);
126 m_length = 0;
127 setIs8Bit(true);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000128 }
129
130public:
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;
utatane.tea@gmail.come0741fb2015-06-02 17:36:16 +0000152 RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const;
darin@apple.com3954c6a2015-06-27 22:53:12 +0000153
154 class SafeView;
155 SafeView view(ExecState*) const;
darin@apple.com6d8af842015-06-24 02:33:18 +0000156 StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const;
darin@apple.com3954c6a2015-06-27 22:53:12 +0000157
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000158 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;
fpizlo@apple.com5b9b41b2015-05-29 20:26:37 +0000164 bool toBoolean() const { return !!m_length; }
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000165 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
ggaren@apple.comc09535a2015-10-06 01:59:02 +0000176 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000177
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 {
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000188 Is8Bit = 1u
189 };
190
191protected:
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000192 friend class JSValue;
193
194 bool isRope() const { return m_value.isNull(); }
akling@apple.com07a49c02015-06-12 04:09:11 +0000195 bool isSubstring() const;
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000196 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 }
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000204
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
211private:
212 friend class LLIntOffsetsExtractor;
213
214 static JSValue toThis(JSCell*, ExecState*, ECMAMode);
215
216 String& string() { ASSERT(!isRope()); return m_value; }
darin@apple.com3954c6a2015-06-27 22:53:12 +0000217 StringView unsafeView(ExecState&) const;
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000218
219 friend JSValue jsString(ExecState*, JSString*, JSString*);
220 friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
221};
222
akling@apple.com4b9e0002015-04-13 19:12:48 +0000223class JSRopeString final : public JSString {
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000224 friend class JSString;
225
226 friend JSRopeString* jsStringBuilder(VM*);
227
utatane.tea@gmail.comec85d882015-01-06 19:33:19 +0000228public:
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000229 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
268private:
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
akling@apple.com07a49c02015-06-12 04:09:11 +0000296 void finishCreation(ExecState& exec, JSString& base, unsigned offset, unsigned length)
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000297 {
akling@apple.com07a49c02015-06-12 04:09:11 +0000298 VM& vm = exec.vm();
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000299 Base::finishCreation(vm);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000300 ASSERT(!sumOverflows<int32_t>(offset, length));
akling@apple.com07a49c02015-06-12 04:09:11 +0000301 ASSERT(offset + length <= base.length());
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000302 m_length = length;
akling@apple.com07a49c02015-06-12 04:09:11 +0000303 setIs8Bit(base.is8Bit());
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000304 setIsSubstring(true);
akling@apple.com07a49c02015-06-12 04:09:11 +0000305 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 }
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000319 }
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
345public:
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
akling@apple.com07a49c02015-06-12 04:09:11 +0000359 static JSString* create(ExecState& exec, JSString& base, unsigned offset, unsigned length)
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000360 {
akling@apple.com07a49c02015-06-12 04:09:11 +0000361 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(exec.vm().heap)) JSRopeString(exec.vm());
362 newString->finishCreation(exec, base, offset, length);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000363 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
372private:
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;
utatane.tea@gmail.come0741fb2015-06-02 17:36:16 +0000378 JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const;
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000379 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;
darin@apple.com3954c6a2015-06-27 22:53:12 +0000387 StringView unsafeView(ExecState&) const;
darin@apple.com6d8af842015-06-24 02:33:18 +0000388 StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const;
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000389
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000390 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
darin@apple.com3954c6a2015-06-27 22:53:12 +0000433class JSString::SafeView {
434public:
435 SafeView();
436 explicit SafeView(ExecState&, const JSString&);
437 operator StringView() const;
438 StringView get() const;
439
440private:
441 ExecState* m_state { nullptr };
442
443 // The following pointer is marked "volatile" to make the compiler leave it on the stack
444 // or in a register as long as this object is alive, even after the last use of the pointer.
445 // That's needed to prevent garbage collecting the string and possibly deleting the block
446 // with the characters in it, and then using the StringView after that.
447 const JSString* volatile m_string { nullptr };
448};
449
450JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000451
452inline const StringImpl* JSString::tryGetValueImpl() const
453{
454 return m_value.impl();
455}
456
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000457inline JSString* asString(JSValue value)
458{
459 ASSERT(value.asCell()->isString());
460 return jsCast<JSString*>(value.asCell());
461}
462
463inline JSString* jsEmptyString(VM* vm)
464{
465 return vm->smallStrings.emptyString();
466}
467
468ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
469{
470 if (c <= maxSingleCharacterString)
471 return vm->smallStrings.singleCharacterString(c);
472 return JSString::create(*vm, String(&c, 1).impl());
473}
474
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000475inline JSString* jsNontrivialString(VM* vm, const String& s)
476{
477 ASSERT(s.length() > 1);
478 return JSString::create(*vm, s.impl());
479}
480
andersca@apple.comc69ac4e2014-10-02 16:14:25 +0000481inline JSString* jsNontrivialString(VM* vm, String&& s)
482{
483 ASSERT(s.length() > 1);
484 return JSString::create(*vm, s.releaseImpl());
485}
486
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000487ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const
488{
utatane.tea@gmail.comb6f60b22015-03-31 21:25:14 +0000489 return Identifier::fromString(exec, toAtomicString(exec));
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000490}
491
492ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const
493{
494 if (isRope())
495 static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
496 return AtomicString(m_value);
497}
498
utatane.tea@gmail.come0741fb2015-06-02 17:36:16 +0000499ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000500{
501 if (isRope())
502 return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec);
503 if (m_value.impl()->isAtomic())
504 return static_cast<AtomicStringImpl*>(m_value.impl());
utatane.tea@gmail.com874750c2015-05-20 04:19:14 +0000505 return AtomicStringImpl::lookUp(m_value.impl());
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000506}
507
508inline const String& JSString::value(ExecState* exec) const
509{
510 if (isRope())
511 static_cast<const JSRopeString*>(this)->resolveRope(exec);
512 return m_value;
513}
514
515inline const String& JSString::tryGetValue() const
516{
517 if (isRope())
518 static_cast<const JSRopeString*>(this)->resolveRope(0);
519 return m_value;
520}
521
522inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
523{
524 ASSERT(canGetIndex(i));
darin@apple.com3954c6a2015-06-27 22:53:12 +0000525 return jsSingleCharacterString(exec, unsafeView(*exec)[i]);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000526}
527
528inline JSString* jsString(VM* vm, const String& s)
529{
530 int size = s.length();
531 if (!size)
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +0000532 return vm->smallStrings.emptyString();
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000533 if (size == 1) {
534 UChar c = s.characterAt(0);
ggaren@apple.come74d2d02011-03-14 22:31:29 +0000535 if (c <= maxSingleCharacterString)
oliver@apple.com7e5973d2013-07-25 04:03:30 +0000536 return vm->smallStrings.singleCharacterString(c);
darin@apple.come7945852008-08-31 06:58:07 +0000537 }
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000538 return JSString::create(*vm, s.impl());
539}
darin@apple.come7945852008-08-31 06:58:07 +0000540
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000541inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
542{
543 ASSERT(offset <= static_cast<unsigned>(s->length()));
544 ASSERT(length <= static_cast<unsigned>(s->length()));
545 ASSERT(offset + length <= static_cast<unsigned>(s->length()));
546 VM& vm = exec->vm();
547 if (!length)
548 return vm.smallStrings.emptyString();
akling@apple.com4ffeb2b2015-06-17 18:54:13 +0000549 if (!offset && length == s->length())
550 return s;
akling@apple.com07a49c02015-06-12 04:09:11 +0000551 return JSRopeString::create(*exec, *s, offset, length);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000552}
553
554inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length)
555{
556 ASSERT(offset <= static_cast<unsigned>(s.length()));
557 ASSERT(length <= static_cast<unsigned>(s.length()));
558 ASSERT(offset + length <= static_cast<unsigned>(s.length()));
559 if (!length)
560 return vm->smallStrings.emptyString();
561 if (length == 1) {
benjamin@webkit.orgc08af732012-08-30 23:41:29 +0000562 UChar c = s.characterAt(offset);
commit-queue@webkit.org7cbe0892014-02-09 08:19:36 +0000563 if (c <= maxSingleCharacterString)
564 return vm->smallStrings.singleCharacterString(c);
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000565 }
566 return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl8(s.impl(), offset, length));
567}
568
569inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
570{
571 ASSERT(offset <= static_cast<unsigned>(s.length()));
572 ASSERT(length <= static_cast<unsigned>(s.length()));
573 ASSERT(offset + length <= static_cast<unsigned>(s.length()));
574 if (!length)
575 return vm->smallStrings.emptyString();
576 if (length == 1) {
577 UChar c = s.characterAt(offset);
578 if (c <= maxSingleCharacterString)
579 return vm->smallStrings.singleCharacterString(c);
580 }
581 return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, length));
582}
583
584inline JSString* jsOwnedString(VM* vm, const String& s)
585{
586 int size = s.length();
587 if (!size)
588 return vm->smallStrings.emptyString();
589 if (size == 1) {
590 UChar c = s.characterAt(0);
591 if (c <= maxSingleCharacterString)
592 return vm->smallStrings.singleCharacterString(c);
593 }
594 return JSString::createHasOtherOwner(*vm, s.impl());
595}
596
597inline JSRopeString* jsStringBuilder(VM* vm)
598{
599 return JSRopeString::createNull(*vm);
600}
601
602inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
603inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
604inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
605inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); }
606inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
607inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
andersca@apple.comc69ac4e2014-10-02 16:14:25 +0000608inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTF::move(s)); }
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000609inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
610
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000611ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s)
612{
613 VM& vm = exec->vm();
614 StringImpl* stringImpl = s.impl();
615 if (!stringImpl || !stringImpl->length())
616 return jsEmptyString(&vm);
617
618 if (stringImpl->length() == 1) {
619 UChar singleCharacter = (*stringImpl)[0u];
620 if (singleCharacter <= maxSingleCharacterString)
621 return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
darin@apple.come7945852008-08-31 06:58:07 +0000622 }
623
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000624 if (JSString* lastCachedString = vm.lastCachedString.get()) {
625 if (lastCachedString->tryGetValueImpl() == stringImpl)
626 return lastCachedString;
darin@apple.come7945852008-08-31 06:58:07 +0000627 }
628
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000629 return jsStringWithCacheSlowCase(vm, *stringImpl);
630}
631
632ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const AtomicString& s)
633{
634 return jsStringWithCache(exec, s.string());
635}
636
637ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
638{
639 if (propertyName == exec->propertyNames().length) {
640 slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length));
641 return true;
akling@apple.com83343ba2014-05-05 18:08:25 +0000642 }
643
utatane.tea@gmail.comc7c203c2015-04-06 12:40:33 +0000644 Optional<uint32_t> index = parseIndex(propertyName);
645 if (index && index.value() < m_length) {
646 slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, index.value()));
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000647 return true;
akling@apple.com63e35432014-05-05 06:24:44 +0000648 }
649
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000650 return false;
651}
652
653ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
654{
655 if (propertyName < m_length) {
656 slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName));
657 return true;
akling@apple.com63e35432014-05-05 06:24:44 +0000658 }
659
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000660 return false;
661}
oliver@apple.com42e59172013-07-25 04:03:27 +0000662
darin@apple.com3954c6a2015-06-27 22:53:12 +0000663inline bool isJSString(JSValue v)
664{
665 return v.isCell() && v.asCell()->type() == StringType;
666}
667
668ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState& state) const
669{
670 if (isSubstring()) {
671 if (is8Bit())
672 return StringView(substringBase()->m_value.characters8() + substringOffset(), m_length);
673 return StringView(substringBase()->m_value.characters16() + substringOffset(), m_length);
674 }
675 resolveRope(&state);
676 return m_value;
677}
678
679ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState& state) const
680{
681 if (isSubstring()) {
682 auto& base = substringBase()->m_value;
683 if (is8Bit())
684 return { { base.characters8() + substringOffset(), m_length }, base };
685 return { { base.characters16() + substringOffset(), m_length }, base };
686 }
687 resolveRope(&state);
688 return { m_value, m_value };
689}
690
691ALWAYS_INLINE StringView JSString::unsafeView(ExecState& state) const
692{
693 if (isRope())
694 return static_cast<const JSRopeString*>(this)->unsafeView(state);
695 return m_value;
696}
697
698ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState& state) const
699{
700 if (isRope())
701 return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(state);
702 return { m_value, m_value };
703}
704
705inline bool JSString::isSubstring() const
706{
707 return isRope() && static_cast<const JSRopeString*>(this)->isSubstring();
708}
709
710inline JSString::SafeView::SafeView()
711{
712}
713
714inline JSString::SafeView::SafeView(ExecState& state, const JSString& string)
715 : m_state(&state)
716 , m_string(&string)
717{
718}
719
720inline JSString::SafeView::operator StringView() const
721{
722 return m_string->unsafeView(*m_state);
723}
724
725inline StringView JSString::SafeView::get() const
726{
727 return *this;
728}
729
730ALWAYS_INLINE JSString::SafeView JSString::view(ExecState* exec) const
731{
732 return SafeView(*exec, *this);
733}
oliver@apple.com42e59172013-07-25 04:03:27 +0000734
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000735// --- JSValue inlines ----------------------------
oliver@apple.com42e59172013-07-25 04:03:27 +0000736
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000737inline bool JSValue::toBoolean(ExecState* exec) const
738{
739 if (isInt32())
740 return asInt32();
741 if (isDouble())
742 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
743 if (isCell())
744 return asCell()->toBoolean(exec);
745 return isTrue(); // false, null, and undefined all convert to false.
746}
oliver@apple.com42e59172013-07-25 04:03:27 +0000747
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000748inline JSString* JSValue::toString(ExecState* exec) const
749{
750 if (isString())
751 return jsCast<JSString*>(asCell());
752 return toStringSlowCase(exec);
753}
oliver@apple.com42e59172013-07-25 04:03:27 +0000754
mark.lam@apple.com188640e2014-09-04 19:10:36 +0000755inline String JSValue::toWTFString(ExecState* exec) const
756{
757 if (isString())
758 return static_cast<JSString*>(asCell())->value(exec);
759 return toWTFStringSlowCase(exec);
760}
oliver@apple.com42e59172013-07-25 04:03:27 +0000761
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +0000762} // namespace JSC
kocienda66a6d362001-08-24 14:24:45 +0000763
weinig@apple.comefdce0f2008-06-30 20:52:03 +0000764#endif // JSString_h