1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef JSString_h
24 #define JSString_h
25 
26 #include "CallFrame.h"
27 #include "CommonIdentifiers.h"
28 #include "Identifier.h"
29 #include "JSNumberCell.h"
30 #include "PropertyDescriptor.h"
31 #include "PropertySlot.h"
32 
33 namespace JSC {
34 
35     class JSString;
36 
37     JSString* jsEmptyString(JSGlobalData*);
38     JSString* jsEmptyString(ExecState*);
39     JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string
40     JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string
41 
42     JSString* jsSingleCharacterString(JSGlobalData*, UChar);
43     JSString* jsSingleCharacterString(ExecState*, UChar);
44     JSString* jsSingleCharacterSubstring(JSGlobalData*, const UString&, unsigned offset);
45     JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset);
46     JSString* jsSubstring(JSGlobalData*, const UString&, unsigned offset, unsigned length);
47     JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length);
48 
49     // Non-trivial strings are two or more characters long.
50     // These functions are faster than just calling jsString.
51     JSString* jsNontrivialString(JSGlobalData*, const UString&);
52     JSString* jsNontrivialString(ExecState*, const UString&);
53     JSString* jsNontrivialString(JSGlobalData*, const char*);
54     JSString* jsNontrivialString(ExecState*, const char*);
55 
56     // Should be used for strings that are owned by an object that will
57     // likely outlive the JSValue this makes, such as the parse tree or a
58     // DOM object that contains a UString
59     JSString* jsOwnedString(JSGlobalData*, const UString&);
60     JSString* jsOwnedString(ExecState*, const UString&);
61 
62     typedef void (*JSStringFinalizerCallback)(JSString*, void* context);
63     JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
64 
65     class JS_EXPORTCLASS JSString : public JSCell {
66     public:
67         friend class JIT;
68         friend class JSGlobalData;
69 
70         // A Rope is a string composed of a set of substrings.
71         class Rope : public RefCounted<Rope> {
72         public:
73             // A Rope is composed from a set of smaller strings called Fibers.
74             // Each Fiber in a rope is either UString::Rep or another Rope.
75             class Fiber {
76             public:
Fiber()77                 Fiber() : m_value(0) {}
Fiber(UString::Rep * string)78                 Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {}
Fiber(Rope * rope)79                 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {}
80 
Fiber(void * nonFiber)81                 Fiber(void* nonFiber) : m_value(reinterpret_cast<intptr_t>(nonFiber)) {}
82 
deref()83                 void deref()
84                 {
85                     if (isRope())
86                         rope()->deref();
87                     else
88                         string()->deref();
89                 }
90 
ref()91                 Fiber& ref()
92                 {
93                     if (isString())
94                         string()->ref();
95                     else
96                         rope()->ref();
97                     return *this;
98                 }
99 
refAndGetLength()100                 unsigned refAndGetLength()
101                 {
102                     if (isString()) {
103                         UString::Rep* rep = string();
104                         return rep->ref()->size();
105                     } else {
106                         Rope* r = rope();
107                         r->ref();
108                         return r->stringLength();
109                     }
110                 }
111 
isRope()112                 bool isRope() { return m_value & 1; }
rope()113                 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); }
isString()114                 bool isString() { return !isRope(); }
string()115                 UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); }
116 
nonFiber()117                 void* nonFiber() { return reinterpret_cast<void*>(m_value); }
118             private:
119                 intptr_t m_value;
120             };
121 
122             // Creates a Rope comprising of 'ropeLength' Fibers.
123             // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope.
createOrNull(unsigned ropeLength)124             static PassRefPtr<Rope> createOrNull(unsigned ropeLength)
125             {
126                 void* allocation;
127                 if (tryFastMalloc(sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(allocation))
128                     return adoptRef(new (allocation) Rope(ropeLength));
129                 return 0;
130             }
131 
132             ~Rope();
133             void destructNonRecursive();
134 
append(unsigned & index,Fiber & fiber)135             void append(unsigned &index, Fiber& fiber)
136             {
137                 m_fibers[index++] = fiber;
138                 m_stringLength += fiber.refAndGetLength();
139             }
append(unsigned & index,const UString & string)140             void append(unsigned &index, const UString& string)
141             {
142                 UString::Rep* rep = string.rep();
143                 m_fibers[index++] = Fiber(rep);
144                 m_stringLength += rep->ref()->size();
145             }
append(unsigned & index,JSString * jsString)146             void append(unsigned& index, JSString* jsString)
147             {
148                 if (jsString->isRope()) {
149                     for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
150                         append(index, jsString->m_fibers[i]);
151                 } else
152                     append(index, jsString->string());
153             }
154 
ropeLength()155             unsigned ropeLength() { return m_ropeLength; }
stringLength()156             unsigned stringLength() { return m_stringLength; }
fibers(unsigned index)157             Fiber& fibers(unsigned index) { return m_fibers[index]; }
158 
159         private:
Rope(unsigned ropeLength)160             Rope(unsigned ropeLength) : m_ropeLength(ropeLength), m_stringLength(0) {}
new(size_t,void * inPlace)161             void* operator new(size_t, void* inPlace) { return inPlace; }
162 
163             unsigned m_ropeLength;
164             unsigned m_stringLength;
165             Fiber m_fibers[1];
166         };
167 
JSString(JSGlobalData * globalData,const UString & value)168         ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value)
169             : JSCell(globalData->stringStructure.get())
170             , m_stringLength(value.size())
171             , m_value(value)
172             , m_ropeLength(0)
173         {
174             Heap::heap(this)->reportExtraMemoryCost(value.cost());
175         }
176 
177         enum HasOtherOwnerType { HasOtherOwner };
JSString(JSGlobalData * globalData,const UString & value,HasOtherOwnerType)178         JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
179             : JSCell(globalData->stringStructure.get())
180             , m_stringLength(value.size())
181             , m_value(value)
182             , m_ropeLength(0)
183         {
184         }
JSString(JSGlobalData * globalData,PassRefPtr<UString::Rep> value,HasOtherOwnerType)185         JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
186             : JSCell(globalData->stringStructure.get())
187             , m_stringLength(value->size())
188             , m_value(value)
189             , m_ropeLength(0)
190         {
191         }
JSString(JSGlobalData * globalData,PassRefPtr<JSString::Rope> rope)192         JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope)
193             : JSCell(globalData->stringStructure.get())
194             , m_stringLength(rope->stringLength())
195             , m_ropeLength(1)
196         {
197             m_fibers[0] = rope.releaseRef();
198         }
199         // This constructor constructs a new string by concatenating s1 & s2.
200         // This should only be called with ropeLength <= 3.
JSString(JSGlobalData * globalData,unsigned ropeLength,JSString * s1,JSString * s2)201         JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2)
202             : JSCell(globalData->stringStructure.get())
203             , m_stringLength(s1->length() + s2->length())
204             , m_ropeLength(ropeLength)
205         {
206             ASSERT(ropeLength <= s_maxInternalRopeLength);
207             unsigned index = 0;
208             appendStringInConstruct(index, s1);
209             appendStringInConstruct(index, s2);
210             ASSERT(ropeLength == index);
211         }
212         // This constructor constructs a new string by concatenating s1 & s2.
213         // This should only be called with ropeLength <= 3.
JSString(JSGlobalData * globalData,unsigned ropeLength,JSString * s1,const UString & u2)214         JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, const UString& u2)
215             : JSCell(globalData->stringStructure.get())
216             , m_stringLength(s1->length() + u2.size())
217             , m_ropeLength(ropeLength)
218         {
219             ASSERT(ropeLength <= s_maxInternalRopeLength);
220             unsigned index = 0;
221             appendStringInConstruct(index, s1);
222             appendStringInConstruct(index, u2);
223             ASSERT(ropeLength == index);
224         }
225         // This constructor constructs a new string by concatenating s1 & s2.
226         // This should only be called with ropeLength <= 3.
JSString(JSGlobalData * globalData,unsigned ropeLength,const UString & u1,JSString * s2)227         JSString(JSGlobalData* globalData, unsigned ropeLength, const UString& u1, JSString* s2)
228             : JSCell(globalData->stringStructure.get())
229             , m_stringLength(u1.size() + s2->length())
230             , m_ropeLength(ropeLength)
231         {
232             ASSERT(ropeLength <= s_maxInternalRopeLength);
233             unsigned index = 0;
234             appendStringInConstruct(index, u1);
235             appendStringInConstruct(index, s2);
236             ASSERT(ropeLength == index);
237         }
238         // This constructor constructs a new string by concatenating v1, v2 & v3.
239         // This should only be called with ropeLength <= 3 ... which since every
240         // value must require a ropeLength of at least one implies that the length
241         // for each value must be exactly 1!
JSString(ExecState * exec,JSValue v1,JSValue v2,JSValue v3)242         JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
243             : JSCell(exec->globalData().stringStructure.get())
244             , m_stringLength(0)
245             , m_ropeLength(s_maxInternalRopeLength)
246         {
247             unsigned index = 0;
248             appendValueInConstructAndIncrementLength(exec, index, v1);
249             appendValueInConstructAndIncrementLength(exec, index, v2);
250             appendValueInConstructAndIncrementLength(exec, index, v3);
251             ASSERT(index == s_maxInternalRopeLength);
252         }
253 
JSString(JSGlobalData * globalData,const UString & value,JSStringFinalizerCallback finalizer,void * context)254         JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context)
255             : JSCell(globalData->stringStructure.get())
256             , m_stringLength(value.size())
257             , m_value(value)
258             , m_ropeLength(0)
259         {
260             // nasty hack because we can't union non-POD types
261             m_fibers[0] = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(finalizer));
262             m_fibers[1] = context;
263             Heap::heap(this)->reportExtraMemoryCost(value.cost());
264         }
265 
~JSString()266         ~JSString()
267         {
268             ASSERT(vptr() == JSGlobalData::jsStringVPtr);
269             for (unsigned i = 0; i < m_ropeLength; ++i)
270                 m_fibers[i].deref();
271 
272             if (!m_ropeLength && m_fibers[0].nonFiber()) {
273                 JSStringFinalizerCallback finalizer = (JSStringFinalizerCallback)(m_fibers[0].nonFiber());
274                 finalizer(this, m_fibers[1].nonFiber());
275             }
276         }
277 
value(ExecState * exec)278         const UString& value(ExecState* exec) const
279         {
280             if (isRope())
281                 resolveRope(exec);
282             return m_value;
283         }
tryGetValue()284         const UString tryGetValue() const
285         {
286             if (isRope())
287                 UString();
288             return m_value;
289         }
length()290         unsigned length() { return m_stringLength; }
291 
292         bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
293         bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
294         bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
295 
canGetIndex(unsigned i)296         bool canGetIndex(unsigned i) { return i < m_stringLength; }
297         JSString* getIndex(ExecState*, unsigned);
298 
createStructure(JSValue proto)299         static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); }
300 
301     private:
302         enum VPtrStealingHackType { VPtrStealingHack };
JSString(VPtrStealingHackType)303         JSString(VPtrStealingHackType)
304             : JSCell(0)
305             , m_ropeLength(0)
306         {
307         }
308 
309         void resolveRope(ExecState*) const;
310 
appendStringInConstruct(unsigned & index,const UString & string)311         void appendStringInConstruct(unsigned& index, const UString& string)
312         {
313             m_fibers[index++] = Rope::Fiber(string.rep()->ref());
314         }
315 
appendStringInConstruct(unsigned & index,JSString * jsString)316         void appendStringInConstruct(unsigned& index, JSString* jsString)
317         {
318             if (jsString->isRope()) {
319                 for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
320                     m_fibers[index++] = jsString->m_fibers[i].ref();
321             } else
322                 appendStringInConstruct(index, jsString->string());
323         }
324 
appendValueInConstructAndIncrementLength(ExecState * exec,unsigned & index,JSValue v)325         void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
326         {
327             if (v.isString()) {
328                 ASSERT(asCell(v)->isString());
329                 JSString* s = static_cast<JSString*>(asCell(v));
330                 ASSERT(s->ropeLength() == 1);
331                 appendStringInConstruct(index, s);
332                 m_stringLength += s->length();
333             } else {
334                 UString u(v.toString(exec));
335                 m_fibers[index++] = Rope::Fiber(u.rep()->ref());
336                 m_stringLength += u.size();
337             }
338         }
339 
340         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
341         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
342         virtual bool toBoolean(ExecState*) const;
343         virtual double toNumber(ExecState*) const;
344         virtual JSObject* toObject(ExecState*) const;
345         virtual UString toString(ExecState*) const;
346 
347         virtual JSObject* toThisObject(ExecState*) const;
348         virtual UString toThisString(ExecState*) const;
349         virtual JSString* toThisJSString(ExecState*);
350 
351         // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
352         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
353         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
354         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
355 
356         static const unsigned s_maxInternalRopeLength = 3;
357 
358         // A string is represented either by a UString or a Rope.
359         unsigned m_stringLength;
360         mutable UString m_value;
361         mutable unsigned m_ropeLength;
362         mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
363 
isRope()364         bool isRope() const { return m_ropeLength; }
string()365         UString& string() { ASSERT(!isRope()); return m_value; }
ropeLength()366         unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; }
367 
368         friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
369         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
370         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
371         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
372         friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
373         friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
374     };
375 
376     JSString* asString(JSValue);
377 
378     // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
379     // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
380     // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
381     // The below function must be called by any inline function that invokes a JSString constructor.
382 #if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
fixupVPtr(JSGlobalData * globalData,JSString * string)383     inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
384 #else
fixupVPtr(JSGlobalData *,JSString * string)385     inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
386 #endif
387 
asString(JSValue value)388     inline JSString* asString(JSValue value)
389     {
390         ASSERT(asCell(value)->isString());
391         return static_cast<JSString*>(asCell(value));
392     }
393 
jsEmptyString(JSGlobalData * globalData)394     inline JSString* jsEmptyString(JSGlobalData* globalData)
395     {
396         return globalData->smallStrings.emptyString(globalData);
397     }
398 
jsSingleCharacterString(JSGlobalData * globalData,UChar c)399     inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
400     {
401         if (c <= 0xFF)
402             return globalData->smallStrings.singleCharacterString(globalData, c);
403         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
404     }
405 
jsSingleCharacterSubstring(JSGlobalData * globalData,const UString & s,unsigned offset)406     inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset)
407     {
408         ASSERT(offset < static_cast<unsigned>(s.size()));
409         UChar c = s.data()[offset];
410         if (c <= 0xFF)
411             return globalData->smallStrings.singleCharacterString(globalData, c);
412         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))));
413     }
414 
jsNontrivialString(JSGlobalData * globalData,const char * s)415     inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
416     {
417         ASSERT(s);
418         ASSERT(s[0]);
419         ASSERT(s[1]);
420         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
421     }
422 
jsNontrivialString(JSGlobalData * globalData,const UString & s)423     inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
424     {
425         ASSERT(s.size() > 1);
426         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
427     }
428 
getIndex(ExecState * exec,unsigned i)429     inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
430     {
431         ASSERT(canGetIndex(i));
432         return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i);
433     }
434 
jsString(JSGlobalData * globalData,const UString & s)435     inline JSString* jsString(JSGlobalData* globalData, const UString& s)
436     {
437         int size = s.size();
438         if (!size)
439             return globalData->smallStrings.emptyString(globalData);
440         if (size == 1) {
441             UChar c = s.data()[0];
442             if (c <= 0xFF)
443                 return globalData->smallStrings.singleCharacterString(globalData, c);
444         }
445         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
446     }
447 
jsStringWithFinalizer(ExecState * exec,const UString & s,JSStringFinalizerCallback callback,void * context)448     inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
449     {
450         ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF));
451         JSGlobalData* globalData = &exec->globalData();
452         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
453     }
454 
jsSubstring(JSGlobalData * globalData,const UString & s,unsigned offset,unsigned length)455     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
456     {
457         ASSERT(offset <= static_cast<unsigned>(s.size()));
458         ASSERT(length <= static_cast<unsigned>(s.size()));
459         ASSERT(offset + length <= static_cast<unsigned>(s.size()));
460         if (!length)
461             return globalData->smallStrings.emptyString(globalData);
462         if (length == 1) {
463             UChar c = s.data()[offset];
464             if (c <= 0xFF)
465                 return globalData->smallStrings.singleCharacterString(globalData, c);
466         }
467         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner));
468     }
469 
jsOwnedString(JSGlobalData * globalData,const UString & s)470     inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
471     {
472         int size = s.size();
473         if (!size)
474             return globalData->smallStrings.emptyString(globalData);
475         if (size == 1) {
476             UChar c = s.data()[0];
477             if (c <= 0xFF)
478                 return globalData->smallStrings.singleCharacterString(globalData, c);
479         }
480         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
481     }
482 
jsEmptyString(ExecState * exec)483     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
jsString(ExecState * exec,const UString & s)484     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
jsSingleCharacterString(ExecState * exec,UChar c)485     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
jsSingleCharacterSubstring(ExecState * exec,const UString & s,unsigned offset)486     inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); }
jsSubstring(ExecState * exec,const UString & s,unsigned offset,unsigned length)487     inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
jsNontrivialString(ExecState * exec,const UString & s)488     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
jsNontrivialString(ExecState * exec,const char * s)489     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
jsOwnedString(ExecState * exec,const UString & s)490     inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); }
491 
getStringPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)492     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
493     {
494         if (propertyName == exec->propertyNames().length) {
495             slot.setValue(jsNumber(exec, m_stringLength));
496             return true;
497         }
498 
499         bool isStrictUInt32;
500         unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
501         if (isStrictUInt32 && i < m_stringLength) {
502             slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i));
503             return true;
504         }
505 
506         return false;
507     }
508 
getStringPropertySlot(ExecState * exec,unsigned propertyName,PropertySlot & slot)509     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
510     {
511         if (propertyName < m_stringLength) {
512             slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName));
513             return true;
514         }
515 
516         return false;
517     }
518 
isJSString(JSGlobalData * globalData,JSValue v)519     inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
520 
521     // --- JSValue inlines ----------------------------
522 
toThisJSString(ExecState * exec)523     inline JSString* JSValue::toThisJSString(ExecState* exec)
524     {
525         return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec));
526     }
527 
toString(ExecState * exec)528     inline UString JSValue::toString(ExecState* exec) const
529     {
530         if (isString())
531             return static_cast<JSString*>(asCell())->value(exec);
532         if (isInt32())
533             return exec->globalData().numericStrings.add(asInt32());
534         if (isDouble())
535             return exec->globalData().numericStrings.add(asDouble());
536         if (isTrue())
537             return "true";
538         if (isFalse())
539             return "false";
540         if (isNull())
541             return "null";
542         if (isUndefined())
543             return "undefined";
544         ASSERT(isCell());
545         return asCell()->toString(exec);
546     }
547 
toPrimitiveString(ExecState * exec)548     inline UString JSValue::toPrimitiveString(ExecState* exec) const
549     {
550         if (isString())
551             return static_cast<JSString*>(asCell())->value(exec);
552         if (isInt32())
553             return exec->globalData().numericStrings.add(asInt32());
554         if (isDouble())
555             return exec->globalData().numericStrings.add(asDouble());
556         if (isTrue())
557             return "true";
558         if (isFalse())
559             return "false";
560         if (isNull())
561             return "null";
562         if (isUndefined())
563             return "undefined";
564         ASSERT(isCell());
565         return asCell()->toPrimitive(exec, NoPreference).toString(exec);
566     }
567 
568 } // namespace JSC
569 
570 #endif // JSString_h
571