• 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 "PropertyDescriptor.h"
30 #include "PropertySlot.h"
31 #include "RopeImpl.h"
32 #include "Structure.h"
33 
34 namespace JSC {
35 
36     class JSString;
37 
38     JSString* jsEmptyString(JSGlobalData*);
39     JSString* jsEmptyString(ExecState*);
40     JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string
41     JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string
42 
43     JSString* jsSingleCharacterString(JSGlobalData*, UChar);
44     JSString* jsSingleCharacterString(ExecState*, UChar);
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         friend class SpecializedThunkJIT;
70         friend struct ThunkHelpers;
71 
72         class RopeBuilder {
73         public:
RopeBuilder(unsigned fiberCount)74             RopeBuilder(unsigned fiberCount)
75                 : m_index(0)
76                 , m_rope(RopeImpl::tryCreateUninitialized(fiberCount))
77             {
78             }
79 
isOutOfMemory()80             bool isOutOfMemory() { return !m_rope; }
81 
append(RopeImpl::Fiber & fiber)82             void append(RopeImpl::Fiber& fiber)
83             {
84                 ASSERT(m_rope);
85                 m_rope->initializeFiber(m_index, fiber);
86             }
append(const UString & string)87             void append(const UString& string)
88             {
89                 ASSERT(m_rope);
90                 m_rope->initializeFiber(m_index, string.impl());
91             }
append(JSString * jsString)92             void append(JSString* jsString)
93             {
94                 if (jsString->isRope()) {
95                     for (unsigned i = 0; i < jsString->m_fiberCount; ++i)
96                         append(jsString->m_other.m_fibers[i]);
97                 } else
98                     append(jsString->string());
99             }
100 
release()101             PassRefPtr<RopeImpl> release()
102             {
103                 ASSERT(m_index == m_rope->fiberCount());
104                 return m_rope.release();
105             }
106 
length()107             unsigned length() { return m_rope->length(); }
108 
109         private:
110             unsigned m_index;
111             RefPtr<RopeImpl> m_rope;
112         };
113 
114         class RopeIterator {
115             public:
RopeIterator()116                 RopeIterator() { }
117 
RopeIterator(RopeImpl::Fiber * fibers,size_t fiberCount)118                 RopeIterator(RopeImpl::Fiber* fibers, size_t fiberCount)
119                 {
120                     ASSERT(fiberCount);
121                     m_workQueue.append(WorkItem(fibers, fiberCount));
122                     skipRopes();
123                 }
124 
125                 RopeIterator& operator++()
126                 {
127                     WorkItem& item = m_workQueue.last();
128                     ASSERT(!RopeImpl::isRope(item.fibers[item.i]));
129                     if (++item.i == item.fiberCount)
130                         m_workQueue.removeLast();
131                     skipRopes();
132                     return *this;
133                 }
134 
135                 StringImpl* operator*()
136                 {
137                     WorkItem& item = m_workQueue.last();
138                     RopeImpl::Fiber fiber = item.fibers[item.i];
139                     ASSERT(!RopeImpl::isRope(fiber));
140                     return static_cast<StringImpl*>(fiber);
141                 }
142 
143                 bool operator!=(const RopeIterator& other) const
144                 {
145                     return m_workQueue != other.m_workQueue;
146                 }
147 
148             private:
149                 struct WorkItem {
WorkItemWorkItem150                     WorkItem(RopeImpl::Fiber* fibers, size_t fiberCount)
151                         : fibers(fibers)
152                         , fiberCount(fiberCount)
153                         , i(0)
154                     {
155                     }
156 
157                     bool operator!=(const WorkItem& other) const
158                     {
159                         return fibers != other.fibers || fiberCount != other.fiberCount || i != other.i;
160                     }
161 
162                     RopeImpl::Fiber* fibers;
163                     size_t fiberCount;
164                     size_t i;
165                 };
166 
skipRopes()167                 void skipRopes()
168                 {
169                     if (m_workQueue.isEmpty())
170                         return;
171 
172                     while (1) {
173                         WorkItem& item = m_workQueue.last();
174                         RopeImpl::Fiber fiber = item.fibers[item.i];
175                         if (!RopeImpl::isRope(fiber))
176                             break;
177                         RopeImpl* rope = static_cast<RopeImpl*>(fiber);
178                         if (++item.i == item.fiberCount)
179                             m_workQueue.removeLast();
180                         m_workQueue.append(WorkItem(rope->fibers(), rope->fiberCount()));
181                     }
182                 }
183 
184                 Vector<WorkItem, 16> m_workQueue;
185         };
186 
JSString(JSGlobalData * globalData,const UString & value)187         ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value)
188             : JSCell(*globalData, globalData->stringStructure.get())
189             , m_length(value.length())
190             , m_value(value)
191             , m_fiberCount(0)
192         {
193             ASSERT(!m_value.isNull());
194             Heap::heap(this)->reportExtraMemoryCost(value.impl()->cost());
195         }
196 
197         enum HasOtherOwnerType { HasOtherOwner };
JSString(JSGlobalData * globalData,const UString & value,HasOtherOwnerType)198         JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
199             : JSCell(*globalData, globalData->stringStructure.get())
200             , m_length(value.length())
201             , m_value(value)
202             , m_fiberCount(0)
203         {
204             ASSERT(!m_value.isNull());
205         }
JSString(JSGlobalData * globalData,PassRefPtr<StringImpl> value,HasOtherOwnerType)206         JSString(JSGlobalData* globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType)
207             : JSCell(*globalData, globalData->stringStructure.get())
208             , m_length(value->length())
209             , m_value(value)
210             , m_fiberCount(0)
211         {
212             ASSERT(!m_value.isNull());
213         }
JSString(JSGlobalData * globalData,PassRefPtr<RopeImpl> rope)214         JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope)
215             : JSCell(*globalData, globalData->stringStructure.get())
216             , m_length(rope->length())
217             , m_fiberCount(1)
218         {
219             m_other.m_fibers[0] = rope.leakRef();
220         }
221         // This constructor constructs a new string by concatenating s1 & s2.
222         // This should only be called with fiberCount <= 3.
JSString(JSGlobalData * globalData,unsigned fiberCount,JSString * s1,JSString * s2)223         JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, JSString* s2)
224             : JSCell(*globalData, globalData->stringStructure.get())
225             , m_length(s1->length() + s2->length())
226             , m_fiberCount(fiberCount)
227         {
228             ASSERT(fiberCount <= s_maxInternalRopeLength);
229             unsigned index = 0;
230             appendStringInConstruct(index, s1);
231             appendStringInConstruct(index, s2);
232             ASSERT(fiberCount == index);
233         }
234         // This constructor constructs a new string by concatenating s1 & s2.
235         // This should only be called with fiberCount <= 3.
JSString(JSGlobalData * globalData,unsigned fiberCount,JSString * s1,const UString & u2)236         JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, const UString& u2)
237             : JSCell(*globalData, globalData->stringStructure.get())
238             , m_length(s1->length() + u2.length())
239             , m_fiberCount(fiberCount)
240         {
241             ASSERT(fiberCount <= s_maxInternalRopeLength);
242             unsigned index = 0;
243             appendStringInConstruct(index, s1);
244             appendStringInConstruct(index, u2);
245             ASSERT(fiberCount == index);
246         }
247         // This constructor constructs a new string by concatenating s1 & s2.
248         // This should only be called with fiberCount <= 3.
JSString(JSGlobalData * globalData,unsigned fiberCount,const UString & u1,JSString * s2)249         JSString(JSGlobalData* globalData, unsigned fiberCount, const UString& u1, JSString* s2)
250             : JSCell(*globalData, globalData->stringStructure.get())
251             , m_length(u1.length() + s2->length())
252             , m_fiberCount(fiberCount)
253         {
254             ASSERT(fiberCount <= s_maxInternalRopeLength);
255             unsigned index = 0;
256             appendStringInConstruct(index, u1);
257             appendStringInConstruct(index, s2);
258             ASSERT(fiberCount == index);
259         }
260         // This constructor constructs a new string by concatenating v1, v2 & v3.
261         // This should only be called with fiberCount <= 3 ... which since every
262         // value must require a fiberCount of at least one implies that the length
263         // for each value must be exactly 1!
JSString(ExecState * exec,JSValue v1,JSValue v2,JSValue v3)264         JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
265             : JSCell(exec->globalData(), exec->globalData().stringStructure.get())
266             , m_length(0)
267             , m_fiberCount(s_maxInternalRopeLength)
268         {
269             unsigned index = 0;
270             appendValueInConstructAndIncrementLength(exec, index, v1);
271             appendValueInConstructAndIncrementLength(exec, index, v2);
272             appendValueInConstructAndIncrementLength(exec, index, v3);
273             ASSERT(index == s_maxInternalRopeLength);
274         }
275 
276         // This constructor constructs a new string by concatenating u1 & u2.
JSString(JSGlobalData * globalData,const UString & u1,const UString & u2)277         JSString(JSGlobalData* globalData, const UString& u1, const UString& u2)
278             : JSCell(*globalData, globalData->stringStructure.get())
279             , m_length(u1.length() + u2.length())
280             , m_fiberCount(2)
281         {
282             unsigned index = 0;
283             appendStringInConstruct(index, u1);
284             appendStringInConstruct(index, u2);
285             ASSERT(index <= s_maxInternalRopeLength);
286         }
287 
288         // This constructor constructs a new string by concatenating u1, u2 & u3.
JSString(JSGlobalData * globalData,const UString & u1,const UString & u2,const UString & u3)289         JSString(JSGlobalData* globalData, const UString& u1, const UString& u2, const UString& u3)
290             : JSCell(*globalData, globalData->stringStructure.get())
291             , m_length(u1.length() + u2.length() + u3.length())
292             , m_fiberCount(s_maxInternalRopeLength)
293         {
294             unsigned index = 0;
295             appendStringInConstruct(index, u1);
296             appendStringInConstruct(index, u2);
297             appendStringInConstruct(index, u3);
298             ASSERT(index <= s_maxInternalRopeLength);
299         }
300 
JSString(JSGlobalData * globalData,const UString & value,JSStringFinalizerCallback finalizer,void * context)301         JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context)
302             : JSCell(*globalData, globalData->stringStructure.get())
303             , m_length(value.length())
304             , m_value(value)
305             , m_fiberCount(0)
306         {
307             ASSERT(!m_value.isNull());
308             // nasty hack because we can't union non-POD types
309             m_other.m_finalizerCallback = finalizer;
310             m_other.m_finalizerContext = context;
311             Heap::heap(this)->reportExtraMemoryCost(value.impl()->cost());
312         }
313 
~JSString()314         ~JSString()
315         {
316             ASSERT(vptr() == JSGlobalData::jsStringVPtr);
317             if (!m_fiberCount) {
318                 if (m_other.m_finalizerCallback)
319                     m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
320             } else {
321                 unsigned i = 0;
322                 do
323                     RopeImpl::deref(m_other.m_fibers[i]);
324                 while (++i < m_fiberCount);
325             }
326         }
327 
value(ExecState * exec)328         const UString& value(ExecState* exec) const
329         {
330             if (isRope())
331                 resolveRope(exec);
332             return m_value;
333         }
tryGetValue()334         const UString& tryGetValue() const
335         {
336             if (isRope())
337                 resolveRope(0);
338             return m_value;
339         }
length()340         unsigned length() { return m_length; }
341 
342         bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
343         bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
344         bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
345 
canGetIndex(unsigned i)346         bool canGetIndex(unsigned i) { return i < m_length; }
347         JSString* getIndex(ExecState*, unsigned);
348         JSString* getIndexSlowCase(ExecState*, unsigned);
349 
350         JSValue replaceCharacter(ExecState*, UChar, const UString& replacement);
351 
createStructure(JSGlobalData & globalData,JSValue proto)352         static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount, 0); }
353 
354     private:
JSString(VPtrStealingHackType)355         JSString(VPtrStealingHackType)
356             : JSCell(VPtrStealingHack)
357             , m_fiberCount(0)
358         {
359         }
360 
361         void resolveRope(ExecState*) const;
362         JSString* substringFromRope(ExecState*, unsigned offset, unsigned length);
363 
appendStringInConstruct(unsigned & index,const UString & string)364         void appendStringInConstruct(unsigned& index, const UString& string)
365         {
366             StringImpl* impl = string.impl();
367             impl->ref();
368             m_other.m_fibers[index++] = impl;
369         }
370 
appendStringInConstruct(unsigned & index,JSString * jsString)371         void appendStringInConstruct(unsigned& index, JSString* jsString)
372         {
373             if (jsString->isRope()) {
374                 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {
375                     RopeImpl::Fiber fiber = jsString->m_other.m_fibers[i];
376                     fiber->ref();
377                     m_other.m_fibers[index++] = fiber;
378                 }
379             } else
380                 appendStringInConstruct(index, jsString->string());
381         }
382 
appendValueInConstructAndIncrementLength(ExecState * exec,unsigned & index,JSValue v)383         void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
384         {
385             if (v.isString()) {
386                 ASSERT(v.asCell()->isString());
387                 JSString* s = static_cast<JSString*>(v.asCell());
388                 ASSERT(s->fiberCount() == 1);
389                 appendStringInConstruct(index, s);
390                 m_length += s->length();
391             } else {
392                 UString u(v.toString(exec));
393                 StringImpl* impl = u.impl();
394                 impl->ref();
395                 m_other.m_fibers[index++] = impl;
396                 m_length += u.length();
397             }
398         }
399 
400         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
401         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
402         virtual bool toBoolean(ExecState*) const;
403         virtual double toNumber(ExecState*) const;
404         virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
405         virtual UString toString(ExecState*) const;
406 
407         virtual JSObject* toThisObject(ExecState*) const;
408 
409         // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
410         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
411         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
412         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
413 
414         static const unsigned s_maxInternalRopeLength = 3;
415 
416         // A string is represented either by a UString or a RopeImpl.
417         unsigned m_length;
418         mutable UString m_value;
419         mutable unsigned m_fiberCount;
420         // This structure exists to support a temporary workaround for a GC issue.
421         struct JSStringFinalizerStruct {
JSStringFinalizerStructJSStringFinalizerStruct422             JSStringFinalizerStruct() : m_finalizerCallback(0) {}
423             union {
424                 mutable FixedArray<RopeImpl::Fiber, s_maxInternalRopeLength> m_fibers;
425                 struct {
426                     JSStringFinalizerCallback m_finalizerCallback;
427                     void* m_finalizerContext;
428                 };
429             };
430         } m_other;
431 
isRope()432         bool isRope() const { return m_fiberCount; }
string()433         UString& string() { ASSERT(!isRope()); return m_value; }
fiberCount()434         unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; }
435 
436         friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
437         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
438         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
439         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
440         friend JSValue jsString(ExecState* exec, JSValue thisValue);
441         friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
442         friend JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length);
443     };
444 
445     JSString* asString(JSValue);
446 
447     // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
448     // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
449     // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
450     // The below function must be called by any inline function that invokes a JSString constructor.
451 #if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
fixupVPtr(JSGlobalData * globalData,JSString * string)452     inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
453 #else
fixupVPtr(JSGlobalData *,JSString * string)454     inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
455 #endif
456 
asString(JSValue value)457     inline JSString* asString(JSValue value)
458     {
459         ASSERT(value.asCell()->isString());
460         return static_cast<JSString*>(value.asCell());
461     }
462 
jsEmptyString(JSGlobalData * globalData)463     inline JSString* jsEmptyString(JSGlobalData* globalData)
464     {
465         return globalData->smallStrings.emptyString(globalData);
466     }
467 
jsSingleCharacterString(JSGlobalData * globalData,UChar c)468     inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
469     {
470         if (c <= maxSingleCharacterString)
471             return globalData->smallStrings.singleCharacterString(globalData, c);
472         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
473     }
474 
jsSingleCharacterSubstring(ExecState * exec,const UString & s,unsigned offset)475     inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
476     {
477         JSGlobalData* globalData = &exec->globalData();
478         ASSERT(offset < static_cast<unsigned>(s.length()));
479         UChar c = s.characters()[offset];
480         if (c <= maxSingleCharacterString)
481             return globalData->smallStrings.singleCharacterString(globalData, c);
482         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, 1))));
483     }
484 
jsNontrivialString(JSGlobalData * globalData,const char * s)485     inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
486     {
487         ASSERT(s);
488         ASSERT(s[0]);
489         ASSERT(s[1]);
490         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
491     }
492 
jsNontrivialString(JSGlobalData * globalData,const UString & s)493     inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
494     {
495         ASSERT(s.length() > 1);
496         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
497     }
498 
getIndex(ExecState * exec,unsigned i)499     inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
500     {
501         ASSERT(canGetIndex(i));
502         if (isRope())
503             return getIndexSlowCase(exec, i);
504         ASSERT(i < m_value.length());
505         return jsSingleCharacterSubstring(exec, m_value, i);
506     }
507 
jsString(JSGlobalData * globalData,const UString & s)508     inline JSString* jsString(JSGlobalData* globalData, const UString& s)
509     {
510         int size = s.length();
511         if (!size)
512             return globalData->smallStrings.emptyString(globalData);
513         if (size == 1) {
514             UChar c = s.characters()[0];
515             if (c <= maxSingleCharacterString)
516                 return globalData->smallStrings.singleCharacterString(globalData, c);
517         }
518         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
519     }
520 
jsStringWithFinalizer(ExecState * exec,const UString & s,JSStringFinalizerCallback callback,void * context)521     inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
522     {
523         ASSERT(s.length() && (s.length() > 1 || s.characters()[0] > maxSingleCharacterString));
524         JSGlobalData* globalData = &exec->globalData();
525         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
526     }
527 
jsSubstring(ExecState * exec,JSString * s,unsigned offset,unsigned length)528     inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
529     {
530         ASSERT(offset <= static_cast<unsigned>(s->length()));
531         ASSERT(length <= static_cast<unsigned>(s->length()));
532         ASSERT(offset + length <= static_cast<unsigned>(s->length()));
533         JSGlobalData* globalData = &exec->globalData();
534         if (!length)
535             return globalData->smallStrings.emptyString(globalData);
536         if (s->isRope())
537             return s->substringFromRope(exec, offset, length);
538         return jsSubstring(globalData, s->m_value, offset, length);
539     }
540 
jsSubstring(JSGlobalData * globalData,const UString & s,unsigned offset,unsigned length)541     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& 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         if (!length)
547             return globalData->smallStrings.emptyString(globalData);
548         if (length == 1) {
549             UChar c = s.characters()[offset];
550             if (c <= maxSingleCharacterString)
551                 return globalData->smallStrings.singleCharacterString(globalData, c);
552         }
553         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, length)), JSString::HasOtherOwner));
554     }
555 
jsOwnedString(JSGlobalData * globalData,const UString & s)556     inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
557     {
558         int size = s.length();
559         if (!size)
560             return globalData->smallStrings.emptyString(globalData);
561         if (size == 1) {
562             UChar c = s.characters()[0];
563             if (c <= maxSingleCharacterString)
564                 return globalData->smallStrings.singleCharacterString(globalData, c);
565         }
566         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
567     }
568 
jsEmptyString(ExecState * exec)569     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
jsString(ExecState * exec,const UString & s)570     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
jsSingleCharacterString(ExecState * exec,UChar c)571     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
jsSubstring(ExecState * exec,const UString & s,unsigned offset,unsigned length)572     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)573     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
jsNontrivialString(ExecState * exec,const char * s)574     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
jsOwnedString(ExecState * exec,const UString & s)575     inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); }
576 
getStringPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)577     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
578     {
579         if (propertyName == exec->propertyNames().length) {
580             slot.setValue(jsNumber(m_length));
581             return true;
582         }
583 
584         bool isStrictUInt32;
585         unsigned i = propertyName.toUInt32(isStrictUInt32);
586         if (isStrictUInt32 && i < m_length) {
587             slot.setValue(getIndex(exec, i));
588             return true;
589         }
590 
591         return false;
592     }
593 
getStringPropertySlot(ExecState * exec,unsigned propertyName,PropertySlot & slot)594     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
595     {
596         if (propertyName < m_length) {
597             slot.setValue(getIndex(exec, propertyName));
598             return true;
599         }
600 
601         return false;
602     }
603 
isJSString(JSGlobalData * globalData,JSValue v)604     inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
605 
606     // --- JSValue inlines ----------------------------
607 
toString(ExecState * exec)608     inline UString JSValue::toString(ExecState* exec) const
609     {
610         if (isString())
611             return static_cast<JSString*>(asCell())->value(exec);
612         if (isInt32())
613             return exec->globalData().numericStrings.add(asInt32());
614         if (isDouble())
615             return exec->globalData().numericStrings.add(asDouble());
616         if (isTrue())
617             return "true";
618         if (isFalse())
619             return "false";
620         if (isNull())
621             return "null";
622         if (isUndefined())
623             return "undefined";
624         ASSERT(isCell());
625         return asCell()->toString(exec);
626     }
627 
toPrimitiveString(ExecState * exec)628     inline UString JSValue::toPrimitiveString(ExecState* exec) const
629     {
630         ASSERT(!isString());
631         if (isInt32())
632             return exec->globalData().numericStrings.add(asInt32());
633         if (isDouble())
634             return exec->globalData().numericStrings.add(asDouble());
635         if (isTrue())
636             return "true";
637         if (isFalse())
638             return "false";
639         if (isNull())
640             return "null";
641         if (isUndefined())
642             return "undefined";
643         ASSERT(isCell());
644         return asCell()->toPrimitive(exec, NoPreference).toString(exec);
645     }
646 
647 } // namespace JSC
648 
649 #endif // JSString_h
650