• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = reinterpret_cast<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 this is a rope, m_value should be null -
287             // if this is not a rope, m_value should be non-null.
288             ASSERT(isRope() == m_value.isNull());
289             return m_value;
290         }
length()291         unsigned length() { return m_stringLength; }
292 
293         bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
294         bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
295         bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
296 
canGetIndex(unsigned i)297         bool canGetIndex(unsigned i) { return i < m_stringLength; }
298         JSString* getIndex(ExecState*, unsigned);
299 
createStructure(JSValue proto)300         static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
301 
302     private:
303         enum VPtrStealingHackType { VPtrStealingHack };
JSString(VPtrStealingHackType)304         JSString(VPtrStealingHackType)
305             : JSCell(0)
306             , m_ropeLength(0)
307         {
308         }
309 
310         void resolveRope(ExecState*) const;
311 
appendStringInConstruct(unsigned & index,const UString & string)312         void appendStringInConstruct(unsigned& index, const UString& string)
313         {
314             m_fibers[index++] = Rope::Fiber(string.rep()->ref());
315         }
316 
appendStringInConstruct(unsigned & index,JSString * jsString)317         void appendStringInConstruct(unsigned& index, JSString* jsString)
318         {
319             if (jsString->isRope()) {
320                 for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
321                     m_fibers[index++] = jsString->m_fibers[i].ref();
322             } else
323                 appendStringInConstruct(index, jsString->string());
324         }
325 
appendValueInConstructAndIncrementLength(ExecState * exec,unsigned & index,JSValue v)326         void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
327         {
328             if (v.isString()) {
329                 ASSERT(asCell(v)->isString());
330                 JSString* s = static_cast<JSString*>(asCell(v));
331                 ASSERT(s->ropeLength() == 1);
332                 appendStringInConstruct(index, s);
333                 m_stringLength += s->length();
334             } else {
335                 UString u(v.toString(exec));
336                 m_fibers[index++] = Rope::Fiber(u.rep()->ref());
337                 m_stringLength += u.size();
338             }
339         }
340 
341         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
342         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
343         virtual bool toBoolean(ExecState*) const;
344         virtual double toNumber(ExecState*) const;
345         virtual JSObject* toObject(ExecState*) const;
346         virtual UString toString(ExecState*) const;
347 
348         virtual JSObject* toThisObject(ExecState*) const;
349         virtual UString toThisString(ExecState*) const;
350         virtual JSString* toThisJSString(ExecState*);
351 
352         // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
353         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
354         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
355         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
356 
357         static const unsigned s_maxInternalRopeLength = 3;
358 
359         // A string is represented either by a UString or a Rope.
360         unsigned m_stringLength;
361         mutable UString m_value;
362         mutable unsigned m_ropeLength;
363         mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
364 
isRope()365         bool isRope() const { return m_ropeLength; }
string()366         UString& string() { ASSERT(!isRope()); return m_value; }
ropeLength()367         unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; }
368 
369         friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
370         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
371         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
372         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
373         friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
374         friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
375     };
376 
377     JSString* asString(JSValue);
378 
379     // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
380     // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
381     // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
382     // The below function must be called by any inline function that invokes a JSString constructor.
383 #if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
fixupVPtr(JSGlobalData * globalData,JSString * string)384     inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
385 #else
fixupVPtr(JSGlobalData *,JSString * string)386     inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
387 #endif
388 
asString(JSValue value)389     inline JSString* asString(JSValue value)
390     {
391         ASSERT(asCell(value)->isString());
392         return static_cast<JSString*>(asCell(value));
393     }
394 
jsEmptyString(JSGlobalData * globalData)395     inline JSString* jsEmptyString(JSGlobalData* globalData)
396     {
397         return globalData->smallStrings.emptyString(globalData);
398     }
399 
jsSingleCharacterString(JSGlobalData * globalData,UChar c)400     inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
401     {
402         if (c <= 0xFF)
403             return globalData->smallStrings.singleCharacterString(globalData, c);
404         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
405     }
406 
jsSingleCharacterSubstring(JSGlobalData * globalData,const UString & s,unsigned offset)407     inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset)
408     {
409         ASSERT(offset < static_cast<unsigned>(s.size()));
410         UChar c = s.data()[offset];
411         if (c <= 0xFF)
412             return globalData->smallStrings.singleCharacterString(globalData, c);
413         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))));
414     }
415 
jsNontrivialString(JSGlobalData * globalData,const char * s)416     inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
417     {
418         ASSERT(s);
419         ASSERT(s[0]);
420         ASSERT(s[1]);
421         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
422     }
423 
jsNontrivialString(JSGlobalData * globalData,const UString & s)424     inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
425     {
426         ASSERT(s.size() > 1);
427         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
428     }
429 
getIndex(ExecState * exec,unsigned i)430     inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
431     {
432         ASSERT(canGetIndex(i));
433         return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i);
434     }
435 
jsString(JSGlobalData * globalData,const UString & s)436     inline JSString* jsString(JSGlobalData* globalData, const UString& s)
437     {
438         int size = s.size();
439         if (!size)
440             return globalData->smallStrings.emptyString(globalData);
441         if (size == 1) {
442             UChar c = s.data()[0];
443             if (c <= 0xFF)
444                 return globalData->smallStrings.singleCharacterString(globalData, c);
445         }
446         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
447     }
448 
jsStringWithFinalizer(ExecState * exec,const UString & s,JSStringFinalizerCallback callback,void * context)449     inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
450     {
451         ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF));
452         JSGlobalData* globalData = &exec->globalData();
453         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
454     }
455 
jsSubstring(JSGlobalData * globalData,const UString & s,unsigned offset,unsigned length)456     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
457     {
458         ASSERT(offset <= static_cast<unsigned>(s.size()));
459         ASSERT(length <= static_cast<unsigned>(s.size()));
460         ASSERT(offset + length <= static_cast<unsigned>(s.size()));
461         if (!length)
462             return globalData->smallStrings.emptyString(globalData);
463         if (length == 1) {
464             UChar c = s.data()[offset];
465             if (c <= 0xFF)
466                 return globalData->smallStrings.singleCharacterString(globalData, c);
467         }
468         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner));
469     }
470 
jsOwnedString(JSGlobalData * globalData,const UString & s)471     inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
472     {
473         int size = s.size();
474         if (!size)
475             return globalData->smallStrings.emptyString(globalData);
476         if (size == 1) {
477             UChar c = s.data()[0];
478             if (c <= 0xFF)
479                 return globalData->smallStrings.singleCharacterString(globalData, c);
480         }
481         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
482     }
483 
jsEmptyString(ExecState * exec)484     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
jsString(ExecState * exec,const UString & s)485     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
jsSingleCharacterString(ExecState * exec,UChar c)486     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
jsSingleCharacterSubstring(ExecState * exec,const UString & s,unsigned offset)487     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)488     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)489     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
jsNontrivialString(ExecState * exec,const char * s)490     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
jsOwnedString(ExecState * exec,const UString & s)491     inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); }
492 
getStringPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)493     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
494     {
495         if (propertyName == exec->propertyNames().length) {
496             slot.setValue(jsNumber(exec, m_stringLength));
497             return true;
498         }
499 
500         bool isStrictUInt32;
501         unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
502         if (isStrictUInt32 && i < m_stringLength) {
503             slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i));
504             return true;
505         }
506 
507         return false;
508     }
509 
getStringPropertySlot(ExecState * exec,unsigned propertyName,PropertySlot & slot)510     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
511     {
512         if (propertyName < m_stringLength) {
513             slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName));
514             return true;
515         }
516 
517         return false;
518     }
519 
isJSString(JSGlobalData * globalData,JSValue v)520     inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
521 
522     // --- JSValue inlines ----------------------------
523 
toThisJSString(ExecState * exec)524     inline JSString* JSValue::toThisJSString(ExecState* exec)
525     {
526         return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec));
527     }
528 
toString(ExecState * exec)529     inline UString JSValue::toString(ExecState* exec) const
530     {
531         if (isString())
532             return static_cast<JSString*>(asCell())->value(exec);
533         if (isInt32())
534             return exec->globalData().numericStrings.add(asInt32());
535         if (isDouble())
536             return exec->globalData().numericStrings.add(asDouble());
537         if (isTrue())
538             return "true";
539         if (isFalse())
540             return "false";
541         if (isNull())
542             return "null";
543         if (isUndefined())
544             return "undefined";
545         ASSERT(isCell());
546         return asCell()->toString(exec);
547     }
548 
toPrimitiveString(ExecState * exec)549     inline UString JSValue::toPrimitiveString(ExecState* exec) const
550     {
551         if (isString())
552             return static_cast<JSString*>(asCell())->value(exec);
553         if (isInt32())
554             return exec->globalData().numericStrings.add(asInt32());
555         if (isDouble())
556             return exec->globalData().numericStrings.add(asDouble());
557         if (isTrue())
558             return "true";
559         if (isFalse())
560             return "false";
561         if (isNull())
562             return "null";
563         if (isUndefined())
564             return "undefined";
565         ASSERT(isCell());
566         return asCell()->toPrimitive(exec, NoPreference).toString(exec);
567     }
568 
569 } // namespace JSC
570 
571 #endif // JSString_h
572