JavaScriptCore/runtime/JSString.h
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
       
     3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
       
     4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
       
     5  *
       
     6  *  This library is free software; you can redistribute it and/or
       
     7  *  modify it under the terms of the GNU Library General Public
       
     8  *  License as published by the Free Software Foundation; either
       
     9  *  version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  *  This library is distributed in the hope that it will be useful,
       
    12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  *  Library General Public License for more details.
       
    15  *
       
    16  *  You should have received a copy of the GNU Library General Public License
       
    17  *  along with this library; see the file COPYING.LIB.  If not, write to
       
    18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    19  *  Boston, MA 02110-1301, USA.
       
    20  *
       
    21  */
       
    22 
       
    23 #ifndef JSString_h
       
    24 #define JSString_h
       
    25 
       
    26 #include "CallFrame.h"
       
    27 #include "CommonIdentifiers.h"
       
    28 #include "Identifier.h"
       
    29 #include "JSNumberCell.h"
       
    30 #include "PropertyDescriptor.h"
       
    31 #include "PropertySlot.h"
       
    32 #include "RopeImpl.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.rep());
       
    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                 UStringImpl* 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<UStringImpl*>(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->stringStructure.get())
       
   189             , m_length(value.size())
       
   190             , m_value(value)
       
   191             , m_fiberCount(0)
       
   192         {
       
   193             ASSERT(!m_value.isNull());
       
   194             Heap::heap(this)->reportExtraMemoryCost(value.cost());
       
   195         }
       
   196 
       
   197         enum HasOtherOwnerType { HasOtherOwner };
       
   198         JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
       
   199             : JSCell(globalData->stringStructure.get())
       
   200             , m_length(value.size())
       
   201             , m_value(value)
       
   202             , m_fiberCount(0)
       
   203         {
       
   204             ASSERT(!m_value.isNull());
       
   205         }
       
   206         JSString(JSGlobalData* globalData, PassRefPtr<UStringImpl> value, HasOtherOwnerType)
       
   207             : JSCell(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->stringStructure.get())
       
   216             , m_length(rope->length())
       
   217             , m_fiberCount(1)
       
   218         {
       
   219             m_other.m_fibers[0] = rope.releaseRef();
       
   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->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->stringStructure.get())
       
   238             , m_length(s1->length() + u2.size())
       
   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->stringStructure.get())
       
   251             , m_length(u1.size() + 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().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->stringStructure.get())
       
   279             , m_length(u1.size() + u2.size())
       
   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->stringStructure.get())
       
   291             , m_length(u1.size() + u2.size() + u3.size())
       
   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->stringStructure.get())
       
   303             , m_length(value.size())
       
   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.cost());
       
   312         }
       
   313 
       
   314         ~JSString()
       
   315         {
       
   316             ASSERT(vptr() == JSGlobalData::jsStringVPtr);
       
   317             for (unsigned i = 0; i < m_fiberCount; ++i)
       
   318                 RopeImpl::deref(m_other.m_fibers[i]);
       
   319 
       
   320             if (!m_fiberCount && m_other.m_finalizerCallback)
       
   321                 m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
       
   322         }
       
   323 
       
   324         const UString& value(ExecState* exec) const
       
   325         {
       
   326             if (isRope())
       
   327                 resolveRope(exec);
       
   328             return m_value;
       
   329         }
       
   330         const UString& tryGetValue() const
       
   331         {
       
   332             if (isRope())
       
   333                 resolveRope(0);
       
   334             return m_value;
       
   335         }
       
   336         unsigned length() { return m_length; }
       
   337 
       
   338         bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
       
   339         bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
       
   340         bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
       
   341 
       
   342         bool canGetIndex(unsigned i) { return i < m_length; }
       
   343         JSString* getIndex(ExecState*, unsigned);
       
   344         JSString* getIndexSlowCase(ExecState*, unsigned);
       
   345 
       
   346         JSValue replaceCharacter(ExecState*, UChar, const UString& replacement);
       
   347 
       
   348         static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
       
   349 
       
   350     private:
       
   351         enum VPtrStealingHackType { VPtrStealingHack };
       
   352         JSString(VPtrStealingHackType) 
       
   353             : JSCell(0)
       
   354             , m_fiberCount(0)
       
   355         {
       
   356         }
       
   357 
       
   358         void resolveRope(ExecState*) const;
       
   359 
       
   360         void appendStringInConstruct(unsigned& index, const UString& string)
       
   361         {
       
   362             UStringImpl* impl = string.rep();
       
   363             impl->ref();
       
   364             m_other.m_fibers[index++] = impl;
       
   365         }
       
   366 
       
   367         void appendStringInConstruct(unsigned& index, JSString* jsString)
       
   368         {
       
   369             if (jsString->isRope()) {
       
   370                 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {
       
   371                     RopeImpl::Fiber fiber = jsString->m_other.m_fibers[i];
       
   372                     fiber->ref();
       
   373                     m_other.m_fibers[index++] = fiber;
       
   374                 }
       
   375             } else
       
   376                 appendStringInConstruct(index, jsString->string());
       
   377         }
       
   378 
       
   379         void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
       
   380         {
       
   381             if (v.isString()) {
       
   382                 ASSERT(asCell(v)->isString());
       
   383                 JSString* s = static_cast<JSString*>(asCell(v));
       
   384                 ASSERT(s->size() == 1);
       
   385                 appendStringInConstruct(index, s);
       
   386                 m_length += s->length();
       
   387             } else {
       
   388                 UString u(v.toString(exec));
       
   389                 UStringImpl* impl = u.rep();
       
   390                 impl->ref();
       
   391                 m_other.m_fibers[index++] = impl;
       
   392                 m_length += u.size();
       
   393             }
       
   394         }
       
   395 
       
   396         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
       
   397         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
       
   398         virtual bool toBoolean(ExecState*) const;
       
   399         virtual double toNumber(ExecState*) const;
       
   400         virtual JSObject* toObject(ExecState*) const;
       
   401         virtual UString toString(ExecState*) const;
       
   402 
       
   403         virtual JSObject* toThisObject(ExecState*) const;
       
   404 
       
   405         // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
       
   406         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
       
   407         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
       
   408         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
       
   409 
       
   410         static const unsigned s_maxInternalRopeLength = 3;
       
   411 
       
   412         // A string is represented either by a UString or a RopeImpl.
       
   413         unsigned m_length;
       
   414         mutable UString m_value;
       
   415         mutable unsigned m_fiberCount;
       
   416         // This structure exists to support a temporary workaround for a GC issue.
       
   417         struct JSStringFinalizerStruct {
       
   418             JSStringFinalizerStruct() : m_finalizerCallback(0) {}
       
   419             union {
       
   420                 mutable FixedArray<RopeImpl::Fiber, s_maxInternalRopeLength> m_fibers;
       
   421                 struct {
       
   422                     JSStringFinalizerCallback m_finalizerCallback;
       
   423                     void* m_finalizerContext;
       
   424                 };
       
   425             };
       
   426         } m_other;
       
   427 
       
   428         bool isRope() const { return m_fiberCount; }
       
   429         UString& string() { ASSERT(!isRope()); return m_value; }
       
   430         unsigned size() { return m_fiberCount ? m_fiberCount : 1; }
       
   431 
       
   432         friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
       
   433         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
       
   434         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
       
   435         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
       
   436         friend JSValue jsString(ExecState* exec, JSValue thisValue);
       
   437         friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
       
   438     };
       
   439 
       
   440     JSString* asString(JSValue);
       
   441 
       
   442     // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
       
   443     // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
       
   444     // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
       
   445     // The below function must be called by any inline function that invokes a JSString constructor.
       
   446 #if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
       
   447     inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
       
   448 #else
       
   449     inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
       
   450 #endif
       
   451 
       
   452     inline JSString* asString(JSValue value)
       
   453     {
       
   454         ASSERT(asCell(value)->isString());
       
   455         return static_cast<JSString*>(asCell(value));
       
   456     }
       
   457 
       
   458     inline JSString* jsEmptyString(JSGlobalData* globalData)
       
   459     {
       
   460         return globalData->smallStrings.emptyString(globalData);
       
   461     }
       
   462 
       
   463     inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
       
   464     {
       
   465         if (c <= 0xFF)
       
   466             return globalData->smallStrings.singleCharacterString(globalData, c);
       
   467         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
       
   468     }
       
   469 
       
   470     inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
       
   471     {
       
   472         JSGlobalData* globalData = &exec->globalData();
       
   473         ASSERT(offset < static_cast<unsigned>(s.size()));
       
   474         UChar c = s.data()[offset];
       
   475         if (c <= 0xFF)
       
   476             return globalData->smallStrings.singleCharacterString(globalData, c);
       
   477         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, 1))));
       
   478     }
       
   479 
       
   480     inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
       
   481     {
       
   482         ASSERT(s);
       
   483         ASSERT(s[0]);
       
   484         ASSERT(s[1]);
       
   485         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
       
   486     }
       
   487 
       
   488     inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
       
   489     {
       
   490         ASSERT(s.size() > 1);
       
   491         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
       
   492     }
       
   493 
       
   494     inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
       
   495     {
       
   496         ASSERT(canGetIndex(i));
       
   497         if (isRope())
       
   498             return getIndexSlowCase(exec, i);
       
   499         ASSERT(i < m_value.size());
       
   500         return jsSingleCharacterSubstring(exec, m_value, i);
       
   501     }
       
   502 
       
   503     inline JSString* jsString(JSGlobalData* globalData, const UString& s)
       
   504     {
       
   505         int size = s.size();
       
   506         if (!size)
       
   507             return globalData->smallStrings.emptyString(globalData);
       
   508         if (size == 1) {
       
   509             UChar c = s.data()[0];
       
   510             if (c <= 0xFF)
       
   511                 return globalData->smallStrings.singleCharacterString(globalData, c);
       
   512         }
       
   513         return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
       
   514     }
       
   515 
       
   516     inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
       
   517     {
       
   518         ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF));
       
   519         JSGlobalData* globalData = &exec->globalData();
       
   520         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
       
   521     }
       
   522 
       
   523     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
       
   524     {
       
   525         ASSERT(offset <= static_cast<unsigned>(s.size()));
       
   526         ASSERT(length <= static_cast<unsigned>(s.size()));
       
   527         ASSERT(offset + length <= static_cast<unsigned>(s.size()));
       
   528         if (!length)
       
   529             return globalData->smallStrings.emptyString(globalData);
       
   530         if (length == 1) {
       
   531             UChar c = s.data()[offset];
       
   532             if (c <= 0xFF)
       
   533                 return globalData->smallStrings.singleCharacterString(globalData, c);
       
   534         }
       
   535         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, length)), JSString::HasOtherOwner));
       
   536     }
       
   537 
       
   538     inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
       
   539     {
       
   540         int size = s.size();
       
   541         if (!size)
       
   542             return globalData->smallStrings.emptyString(globalData);
       
   543         if (size == 1) {
       
   544             UChar c = s.data()[0];
       
   545             if (c <= 0xFF)
       
   546                 return globalData->smallStrings.singleCharacterString(globalData, c);
       
   547         }
       
   548         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
       
   549     }
       
   550 
       
   551     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
       
   552     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
       
   553     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
       
   554     inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
       
   555     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
       
   556     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
       
   557     inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); } 
       
   558 
       
   559     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
       
   560     {
       
   561         if (propertyName == exec->propertyNames().length) {
       
   562             slot.setValue(jsNumber(exec, m_length));
       
   563             return true;
       
   564         }
       
   565 
       
   566         bool isStrictUInt32;
       
   567         unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
       
   568         if (isStrictUInt32 && i < m_length) {
       
   569             slot.setValue(getIndex(exec, i));
       
   570             return true;
       
   571         }
       
   572 
       
   573         return false;
       
   574     }
       
   575         
       
   576     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
       
   577     {
       
   578         if (propertyName < m_length) {
       
   579             slot.setValue(getIndex(exec, propertyName));
       
   580             return true;
       
   581         }
       
   582 
       
   583         return false;
       
   584     }
       
   585 
       
   586     inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
       
   587 
       
   588     // --- JSValue inlines ----------------------------
       
   589 
       
   590     inline UString JSValue::toString(ExecState* exec) const
       
   591     {
       
   592         if (isString())
       
   593             return static_cast<JSString*>(asCell())->value(exec);
       
   594         if (isInt32())
       
   595             return exec->globalData().numericStrings.add(asInt32());
       
   596         if (isDouble())
       
   597             return exec->globalData().numericStrings.add(asDouble());
       
   598         if (isTrue())
       
   599             return "true";
       
   600         if (isFalse())
       
   601             return "false";
       
   602         if (isNull())
       
   603             return "null";
       
   604         if (isUndefined())
       
   605             return "undefined";
       
   606         ASSERT(isCell());
       
   607         return asCell()->toString(exec);
       
   608     }
       
   609 
       
   610     inline UString JSValue::toPrimitiveString(ExecState* exec) const
       
   611     {
       
   612         if (isString())
       
   613             return static_cast<JSString*>(asCell())->value(exec);
       
   614         if (isInt32())
       
   615             return exec->globalData().numericStrings.add(asInt32());
       
   616         if (isDouble())
       
   617             return exec->globalData().numericStrings.add(asDouble());
       
   618         if (isTrue())
       
   619             return "true";
       
   620         if (isFalse())
       
   621             return "false";
       
   622         if (isNull())
       
   623             return "null";
       
   624         if (isUndefined())
       
   625             return "undefined";
       
   626         ASSERT(isCell());
       
   627         return asCell()->toPrimitive(exec, NoPreference).toString(exec);
       
   628     }
       
   629 
       
   630 } // namespace JSC
       
   631 
       
   632 #endif // JSString_h