Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 1999-2001 Harri Porten (porten (at) kde.org)
      3  *  Copyright (C) 2001 Peter Kelly (pmk (at) 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:
     74             RopeBuilder(unsigned fiberCount)
     75                 : m_index(0)
     76                 , m_rope(RopeImpl::tryCreateUninitialized(fiberCount))
     77             {
     78             }
     79 
     80             bool isOutOfMemory() { return !m_rope; }
     81 
     82             void append(RopeImpl::Fiber& fiber)
     83             {
     84                 ASSERT(m_rope);
     85                 m_rope->initializeFiber(m_index, fiber);
     86             }
     87             void append(const UString& string)
     88             {
     89                 ASSERT(m_rope);
     90                 m_rope->initializeFiber(m_index, string.impl());
     91             }
     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 
    101             PassRefPtr<RopeImpl> release()
    102             {
    103                 ASSERT(m_index == m_rope->fiberCount());
    104                 return m_rope.release();
    105             }
    106 
    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:
    116                 RopeIterator() { }
    117 
    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 {
    150                     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 
    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 
    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 };
    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         }
    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         }
    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.
    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.
    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.
    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!
    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.
    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.
    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 
    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 
    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 
    328         const UString& value(ExecState* exec) const
    329         {
    330             if (isRope())
    331                 resolveRope(exec);
    332             return m_value;
    333         }
    334         const UString& tryGetValue() const
    335         {
    336             if (isRope())
    337                 resolveRope(0);
    338             return m_value;
    339         }
    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 
    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 
    352         static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount, 0); }
    353 
    354     private:
    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 
    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 
    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 
    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 {
    422             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 
    432         bool isRope() const { return m_fiberCount; }
    433         UString& string() { ASSERT(!isRope()); return m_value; }
    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)
    452     inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
    453 #else
    454     inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
    455 #endif
    456 
    457     inline JSString* asString(JSValue value)
    458     {
    459         ASSERT(value.asCell()->isString());
    460         return static_cast<JSString*>(value.asCell());
    461     }
    462 
    463     inline JSString* jsEmptyString(JSGlobalData* globalData)
    464     {
    465         return globalData->smallStrings.emptyString(globalData);
    466     }
    467 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    569     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
    570     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
    571     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
    572     inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
    573     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
    574     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
    575     inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); }
    576 
    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 
    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 
    604     inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
    605 
    606     // --- JSValue inlines ----------------------------
    607 
    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 
    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