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