| 1 | /* | 
| 2 |  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | 
| 3 |  *  Copyright (C) 2001 Peter Kelly (pmk@post.com) | 
| 4 |  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 
| 5 |  * | 
| 6 |  *  This library is free software; you can redistribute it and/or | 
| 7 |  *  modify it under the terms of the GNU Library General Public | 
| 8 |  *  License as published by the Free Software Foundation; either | 
| 9 |  *  version 2 of the License, or (at your option) any later version. | 
| 10 |  * | 
| 11 |  *  This library is distributed in the hope that it will be useful, | 
| 12 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 13 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
| 14 |  *  Library General Public License for more details. | 
| 15 |  * | 
| 16 |  *  You should have received a copy of the GNU Library General Public License | 
| 17 |  *  along with this library; see the file COPYING.LIB.  If not, write to | 
| 18 |  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
| 19 |  *  Boston, MA 02110-1301, USA. | 
| 20 |  * | 
| 21 |  */ | 
| 22 |  | 
| 23 | #ifndef JSString_h | 
| 24 | #define JSString_h | 
| 25 |  | 
| 26 | #include "CallFrame.h" | 
| 27 | #include "CommonIdentifiers.h" | 
| 28 | #include "Identifier.h" | 
| 29 | #include "JSNumberCell.h" | 
| 30 | #include "PropertyDescriptor.h" | 
| 31 | #include "PropertySlot.h" | 
| 32 |  | 
| 33 | namespace JSC { | 
| 34 |  | 
| 35 |     class JSString; | 
| 36 |  | 
| 37 |     JSString* jsEmptyString(JSGlobalData*); | 
| 38 |     JSString* jsEmptyString(ExecState*); | 
| 39 |     JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string | 
| 40 |     JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string | 
| 41 |  | 
| 42 |     JSString* jsSingleCharacterString(JSGlobalData*, UChar); | 
| 43 |     JSString* jsSingleCharacterString(ExecState*, UChar); | 
| 44 |     JSString* jsSingleCharacterSubstring(JSGlobalData*, const UString&, unsigned offset); | 
| 45 |     JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset); | 
| 46 |     JSString* jsSubstring(JSGlobalData*, const UString&, unsigned offset, unsigned length); | 
| 47 |     JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length); | 
| 48 |  | 
| 49 |     // Non-trivial strings are two or more characters long. | 
| 50 |     // These functions are faster than just calling jsString. | 
| 51 |     JSString* jsNontrivialString(JSGlobalData*, const UString&); | 
| 52 |     JSString* jsNontrivialString(ExecState*, const UString&); | 
| 53 |     JSString* jsNontrivialString(JSGlobalData*, const char*); | 
| 54 |     JSString* jsNontrivialString(ExecState*, const char*); | 
| 55 |  | 
| 56 |     // Should be used for strings that are owned by an object that will | 
| 57 |     // likely outlive the JSValue this makes, such as the parse tree or a | 
| 58 |     // DOM object that contains a UString | 
| 59 |     JSString* jsOwnedString(JSGlobalData*, const UString&);  | 
| 60 |     JSString* jsOwnedString(ExecState*, const UString&);  | 
| 61 |  | 
| 62 |     typedef void (*JSStringFinalizerCallback)(JSString*, void* context); | 
| 63 |     JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context); | 
| 64 |  | 
| 65 |     class JS_EXPORTCLASS JSString : public JSCell { | 
| 66 |     public: | 
| 67 |         friend class JIT; | 
| 68 |         friend class JSGlobalData; | 
| 69 |  | 
| 70 |         // A Rope is a string composed of a set of substrings. | 
| 71 |         class Rope : public RefCounted<Rope> { | 
| 72 |         public: | 
| 73 |             // A Rope is composed from a set of smaller strings called Fibers. | 
| 74 |             // Each Fiber in a rope is either UString::Rep or another Rope. | 
| 75 |             class Fiber { | 
| 76 |             public: | 
| 77 |                 Fiber() : m_value(0) {} | 
| 78 |                 Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {} | 
| 79 |                 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {} | 
| 80 |  | 
| 81 |                 Fiber(void* nonFiber) : m_value(reinterpret_cast<intptr_t>(nonFiber)) {} | 
| 82 |  | 
| 83 |                 void deref() | 
| 84 |                 { | 
| 85 |                     if (isRope()) | 
| 86 |                         rope()->deref(); | 
| 87 |                     else | 
| 88 |                         string()->deref(); | 
| 89 |                 } | 
| 90 |  | 
| 91 |                 Fiber& ref() | 
| 92 |                 { | 
| 93 |                     if (isString()) | 
| 94 |                         string()->ref(); | 
| 95 |                     else | 
| 96 |                         rope()->ref(); | 
| 97 |                     return *this; | 
| 98 |                 } | 
| 99 |  | 
| 100 |                 unsigned refAndGetLength() | 
| 101 |                 { | 
| 102 |                     if (isString()) { | 
| 103 |                         UString::Rep* rep = string(); | 
| 104 |                         return rep->ref()->size(); | 
| 105 |                     } else { | 
| 106 |                         Rope* r = rope(); | 
| 107 |                         r->ref(); | 
| 108 |                         return r->stringLength(); | 
| 109 |                     } | 
| 110 |                 } | 
| 111 |  | 
| 112 |                 bool isRope() { return m_value & 1; } | 
| 113 |                 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); } | 
| 114 |                 bool isString() { return !isRope(); } | 
| 115 |                 UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); } | 
| 116 |  | 
| 117 |                 void* nonFiber() { return reinterpret_cast<void*>(m_value); } | 
| 118 |             private: | 
| 119 |                 intptr_t m_value; | 
| 120 |             }; | 
| 121 |  | 
| 122 |             // Creates a Rope comprising of 'ropeLength' Fibers. | 
| 123 |             // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope. | 
| 124 |             static PassRefPtr<Rope> createOrNull(unsigned ropeLength) | 
| 125 |             { | 
| 126 |                 void* allocation; | 
| 127 |                 if (tryFastMalloc(n: sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(data&: allocation)) | 
| 128 |                     return adoptRef(p: new (allocation) Rope(ropeLength)); | 
| 129 |                 return 0; | 
| 130 |             } | 
| 131 |  | 
| 132 |             ~Rope(); | 
| 133 |             void destructNonRecursive(); | 
| 134 |  | 
| 135 |             void append(unsigned &index, Fiber& fiber) | 
| 136 |             { | 
| 137 |                 m_fibers[index++] = fiber; | 
| 138 |                 m_stringLength += fiber.refAndGetLength(); | 
| 139 |             } | 
| 140 |             void append(unsigned &index, const UString& string) | 
| 141 |             { | 
| 142 |                 UString::Rep* rep = string.rep(); | 
| 143 |                 m_fibers[index++] = Fiber(rep); | 
| 144 |                 m_stringLength += rep->ref()->size(); | 
| 145 |             } | 
| 146 |             void append(unsigned& index, JSString* jsString) | 
| 147 |             { | 
| 148 |                 if (jsString->isRope()) { | 
| 149 |                     for (unsigned i = 0; i < jsString->m_ropeLength; ++i) | 
| 150 |                         append(index, fiber&: jsString->m_fibers[i]); | 
| 151 |                 } else | 
| 152 |                     append(index, string: jsString->string()); | 
| 153 |             } | 
| 154 |  | 
| 155 |             unsigned ropeLength() { return m_ropeLength; } | 
| 156 |             unsigned stringLength() { return m_stringLength; } | 
| 157 |             Fiber& fibers(unsigned index) { return m_fibers[index]; } | 
| 158 |  | 
| 159 |         private: | 
| 160 |             Rope(unsigned ropeLength) : m_ropeLength(ropeLength), m_stringLength(0) {} | 
| 161 |             void* operator new(size_t, void* inPlace) { return inPlace; } | 
| 162 |              | 
| 163 |             unsigned m_ropeLength; | 
| 164 |             unsigned m_stringLength; | 
| 165 |             Fiber m_fibers[1]; | 
| 166 |         }; | 
| 167 |  | 
| 168 |         ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value) | 
| 169 |             : JSCell(globalData->stringStructure.get()) | 
| 170 |             , m_stringLength(value.size()) | 
| 171 |             , m_value(value) | 
| 172 |             , m_ropeLength(0) | 
| 173 |         { | 
| 174 |             Heap::heap(c: this)->reportExtraMemoryCost(cost: value.cost()); | 
| 175 |         } | 
| 176 |  | 
| 177 |         enum HasOtherOwnerType { HasOtherOwner }; | 
| 178 |         JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) | 
| 179 |             : JSCell(globalData->stringStructure.get()) | 
| 180 |             , m_stringLength(value.size()) | 
| 181 |             , m_value(value) | 
| 182 |             , m_ropeLength(0) | 
| 183 |         { | 
| 184 |         } | 
| 185 |         JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) | 
| 186 |             : JSCell(globalData->stringStructure.get()) | 
| 187 |             , m_stringLength(value->size()) | 
| 188 |             , m_value(value) | 
| 189 |             , m_ropeLength(0) | 
| 190 |         { | 
| 191 |         } | 
| 192 |         JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope) | 
| 193 |             : JSCell(globalData->stringStructure.get()) | 
| 194 |             , m_stringLength(rope->stringLength()) | 
| 195 |             , m_ropeLength(1) | 
| 196 |         { | 
| 197 |             m_fibers[0] = rope.releaseRef(); | 
| 198 |         } | 
| 199 |         // This constructor constructs a new string by concatenating s1 & s2. | 
| 200 |         // This should only be called with ropeLength <= 3. | 
| 201 |         JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2) | 
| 202 |             : JSCell(globalData->stringStructure.get()) | 
| 203 |             , m_stringLength(s1->length() + s2->length()) | 
| 204 |             , m_ropeLength(ropeLength) | 
| 205 |         { | 
| 206 |             ASSERT(ropeLength <= s_maxInternalRopeLength); | 
| 207 |             unsigned index = 0; | 
| 208 |             appendStringInConstruct(index, jsString: s1); | 
| 209 |             appendStringInConstruct(index, jsString: s2); | 
| 210 |             ASSERT(ropeLength == index); | 
| 211 |         } | 
| 212 |         // This constructor constructs a new string by concatenating s1 & s2. | 
| 213 |         // This should only be called with ropeLength <= 3. | 
| 214 |         JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, const UString& u2) | 
| 215 |             : JSCell(globalData->stringStructure.get()) | 
| 216 |             , m_stringLength(s1->length() + u2.size()) | 
| 217 |             , m_ropeLength(ropeLength) | 
| 218 |         { | 
| 219 |             ASSERT(ropeLength <= s_maxInternalRopeLength); | 
| 220 |             unsigned index = 0; | 
| 221 |             appendStringInConstruct(index, jsString: s1); | 
| 222 |             appendStringInConstruct(index, string: u2); | 
| 223 |             ASSERT(ropeLength == index); | 
| 224 |         } | 
| 225 |         // This constructor constructs a new string by concatenating s1 & s2. | 
| 226 |         // This should only be called with ropeLength <= 3. | 
| 227 |         JSString(JSGlobalData* globalData, unsigned ropeLength, const UString& u1, JSString* s2) | 
| 228 |             : JSCell(globalData->stringStructure.get()) | 
| 229 |             , m_stringLength(u1.size() + s2->length()) | 
| 230 |             , m_ropeLength(ropeLength) | 
| 231 |         { | 
| 232 |             ASSERT(ropeLength <= s_maxInternalRopeLength); | 
| 233 |             unsigned index = 0; | 
| 234 |             appendStringInConstruct(index, string: u1); | 
| 235 |             appendStringInConstruct(index, jsString: s2); | 
| 236 |             ASSERT(ropeLength == index); | 
| 237 |         } | 
| 238 |         // This constructor constructs a new string by concatenating v1, v2 & v3. | 
| 239 |         // This should only be called with ropeLength <= 3 ... which since every | 
| 240 |         // value must require a ropeLength of at least one implies that the length | 
| 241 |         // for each value must be exactly 1! | 
| 242 |         JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) | 
| 243 |             : JSCell(exec->globalData().stringStructure.get()) | 
| 244 |             , m_stringLength(0) | 
| 245 |             , m_ropeLength(s_maxInternalRopeLength) | 
| 246 |         { | 
| 247 |             unsigned index = 0; | 
| 248 |             appendValueInConstructAndIncrementLength(exec, index, v: v1); | 
| 249 |             appendValueInConstructAndIncrementLength(exec, index, v: v2); | 
| 250 |             appendValueInConstructAndIncrementLength(exec, index, v: v3); | 
| 251 |             ASSERT(index == s_maxInternalRopeLength); | 
| 252 |         } | 
| 253 |  | 
| 254 |         JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context) | 
| 255 |             : JSCell(globalData->stringStructure.get()) | 
| 256 |             , m_stringLength(value.size()) | 
| 257 |             , m_value(value) | 
| 258 |             , m_ropeLength(0) | 
| 259 |         { | 
| 260 |             // nasty hack because we can't union non-POD types | 
| 261 |             m_fibers[0] = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(finalizer)); | 
| 262 |             m_fibers[1] = context; | 
| 263 |             Heap::heap(c: this)->reportExtraMemoryCost(cost: value.cost()); | 
| 264 |         } | 
| 265 |  | 
| 266 |         ~JSString() | 
| 267 |         { | 
| 268 |             ASSERT(vptr() == JSGlobalData::jsStringVPtr); | 
| 269 |             for (unsigned i = 0; i < m_ropeLength; ++i) | 
| 270 |                 m_fibers[i].deref(); | 
| 271 |  | 
| 272 |             if (!m_ropeLength && m_fibers[0].nonFiber()) { | 
| 273 |                 JSStringFinalizerCallback finalizer = (JSStringFinalizerCallback)(m_fibers[0].nonFiber()); | 
| 274 |                 finalizer(this, m_fibers[1].nonFiber()); | 
| 275 |             } | 
| 276 |         } | 
| 277 |  | 
| 278 |         const UString& value(ExecState* exec) const | 
| 279 |         { | 
| 280 |             if (isRope()) | 
| 281 |                 resolveRope(exec); | 
| 282 |             return m_value; | 
| 283 |         } | 
| 284 |         const UString tryGetValue() const | 
| 285 |         { | 
| 286 |             if (isRope()) | 
| 287 |                 UString(); | 
| 288 |             return m_value; | 
| 289 |         } | 
| 290 |         unsigned length() { return m_stringLength; } | 
| 291 |  | 
| 292 |         bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | 
| 293 |         bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); | 
| 294 |         bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); | 
| 295 |  | 
| 296 |         bool canGetIndex(unsigned i) { return i < m_stringLength; } | 
| 297 |         JSString* getIndex(ExecState*, unsigned); | 
| 298 |  | 
| 299 |         static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(prototype: proto, typeInfo: TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); } | 
| 300 |  | 
| 301 |     private: | 
| 302 |         enum VPtrStealingHackType { VPtrStealingHack }; | 
| 303 |         JSString(VPtrStealingHackType)  | 
| 304 |             : JSCell(0) | 
| 305 |             , m_ropeLength(0) | 
| 306 |         { | 
| 307 |         } | 
| 308 |  | 
| 309 |         void resolveRope(ExecState*) const; | 
| 310 |  | 
| 311 |         void appendStringInConstruct(unsigned& index, const UString& string) | 
| 312 |         { | 
| 313 |             m_fibers[index++] = Rope::Fiber(string.rep()->ref()); | 
| 314 |         } | 
| 315 |  | 
| 316 |         void appendStringInConstruct(unsigned& index, JSString* jsString) | 
| 317 |         { | 
| 318 |             if (jsString->isRope()) { | 
| 319 |                 for (unsigned i = 0; i < jsString->m_ropeLength; ++i) | 
| 320 |                     m_fibers[index++] = jsString->m_fibers[i].ref(); | 
| 321 |             } else | 
| 322 |                 appendStringInConstruct(index, string: jsString->string()); | 
| 323 |         } | 
| 324 |  | 
| 325 |         void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v) | 
| 326 |         { | 
| 327 |             if (v.isString()) { | 
| 328 |                 ASSERT(asCell(v)->isString()); | 
| 329 |                 JSString* s = static_cast<JSString*>(asCell(value: v)); | 
| 330 |                 ASSERT(s->ropeLength() == 1); | 
| 331 |                 appendStringInConstruct(index, jsString: s); | 
| 332 |                 m_stringLength += s->length(); | 
| 333 |             } else { | 
| 334 |                 UString u(v.toString(exec)); | 
| 335 |                 m_fibers[index++] = Rope::Fiber(u.rep()->ref()); | 
| 336 |                 m_stringLength += u.size(); | 
| 337 |             } | 
| 338 |         } | 
| 339 |  | 
| 340 |         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; | 
| 341 |         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); | 
| 342 |         virtual bool toBoolean(ExecState*) const; | 
| 343 |         virtual double toNumber(ExecState*) const; | 
| 344 |         virtual JSObject* toObject(ExecState*) const; | 
| 345 |         virtual UString toString(ExecState*) const; | 
| 346 |  | 
| 347 |         virtual JSObject* toThisObject(ExecState*) const; | 
| 348 |         virtual UString toThisString(ExecState*) const; | 
| 349 |         virtual JSString* toThisJSString(ExecState*); | 
| 350 |  | 
| 351 |         // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). | 
| 352 |         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | 
| 353 |         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); | 
| 354 |         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); | 
| 355 |  | 
| 356 |         static const unsigned s_maxInternalRopeLength = 3; | 
| 357 |  | 
| 358 |         // A string is represented either by a UString or a Rope. | 
| 359 |         unsigned m_stringLength; | 
| 360 |         mutable UString m_value; | 
| 361 |         mutable unsigned m_ropeLength; | 
| 362 |         mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; | 
| 363 |  | 
| 364 |         bool isRope() const { return m_ropeLength; } | 
| 365 |         UString& string() { ASSERT(!isRope()); return m_value; } | 
| 366 |         unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; } | 
| 367 |  | 
| 368 |         friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); | 
| 369 |         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2); | 
| 370 |         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2); | 
| 371 |         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count); | 
| 372 |         friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args); | 
| 373 |         friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context); | 
| 374 |     }; | 
| 375 |  | 
| 376 |     JSString* asString(JSValue); | 
| 377 |  | 
| 378 |     // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor, | 
| 379 |     // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>. | 
| 380 |     // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one. | 
| 381 |     // The below function must be called by any inline function that invokes a JSString constructor. | 
| 382 | #if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore) | 
| 383 |     inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; } | 
| 384 | #else | 
| 385 |     inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; } | 
| 386 | #endif | 
| 387 |  | 
| 388 |     inline JSString* asString(JSValue value) | 
| 389 |     { | 
| 390 |         ASSERT(asCell(value)->isString()); | 
| 391 |         return static_cast<JSString*>(asCell(value)); | 
| 392 |     } | 
| 393 |  | 
| 394 |     inline JSString* jsEmptyString(JSGlobalData* globalData) | 
| 395 |     { | 
| 396 |         return globalData->smallStrings.emptyString(globalData); | 
| 397 |     } | 
| 398 |  | 
| 399 |     inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) | 
| 400 |     { | 
| 401 |         if (c <= 0xFF) | 
| 402 |             return globalData->smallStrings.singleCharacterString(globalData, character: c); | 
| 403 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, UString(&c, 1))); | 
| 404 |     } | 
| 405 |  | 
| 406 |     inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset) | 
| 407 |     { | 
| 408 |         ASSERT(offset < static_cast<unsigned>(s.size())); | 
| 409 |         UChar c = s.data()[offset]; | 
| 410 |         if (c <= 0xFF) | 
| 411 |             return globalData->smallStrings.singleCharacterString(globalData, character: c); | 
| 412 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, UString(UString::Rep::create(rep: s.rep(), offset, length: 1)))); | 
| 413 |     } | 
| 414 |  | 
| 415 |     inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) | 
| 416 |     { | 
| 417 |         ASSERT(s); | 
| 418 |         ASSERT(s[0]); | 
| 419 |         ASSERT(s[1]); | 
| 420 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, s)); | 
| 421 |     } | 
| 422 |  | 
| 423 |     inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s) | 
| 424 |     { | 
| 425 |         ASSERT(s.size() > 1); | 
| 426 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, s)); | 
| 427 |     } | 
| 428 |  | 
| 429 |     inline JSString* JSString::getIndex(ExecState* exec, unsigned i) | 
| 430 |     { | 
| 431 |         ASSERT(canGetIndex(i)); | 
| 432 |         return jsSingleCharacterSubstring(globalData: &exec->globalData(), s: value(exec), offset: i); | 
| 433 |     } | 
| 434 |  | 
| 435 |     inline JSString* jsString(JSGlobalData* globalData, const UString& s) | 
| 436 |     { | 
| 437 |         int size = s.size(); | 
| 438 |         if (!size) | 
| 439 |             return globalData->smallStrings.emptyString(globalData); | 
| 440 |         if (size == 1) { | 
| 441 |             UChar c = s.data()[0]; | 
| 442 |             if (c <= 0xFF) | 
| 443 |                 return globalData->smallStrings.singleCharacterString(globalData, character: c); | 
| 444 |         } | 
| 445 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, s)); | 
| 446 |     } | 
| 447 |  | 
| 448 |     inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context) | 
| 449 |     { | 
| 450 |         ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF)); | 
| 451 |         JSGlobalData* globalData = &exec->globalData(); | 
| 452 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, s, callback, context)); | 
| 453 |     } | 
| 454 |  | 
| 455 |     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) | 
| 456 |     { | 
| 457 |         ASSERT(offset <= static_cast<unsigned>(s.size())); | 
| 458 |         ASSERT(length <= static_cast<unsigned>(s.size())); | 
| 459 |         ASSERT(offset + length <= static_cast<unsigned>(s.size())); | 
| 460 |         if (!length) | 
| 461 |             return globalData->smallStrings.emptyString(globalData); | 
| 462 |         if (length == 1) { | 
| 463 |             UChar c = s.data()[offset]; | 
| 464 |             if (c <= 0xFF) | 
| 465 |                 return globalData->smallStrings.singleCharacterString(globalData, character: c); | 
| 466 |         } | 
| 467 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, UString(UString::Rep::create(rep: s.rep(), offset, length)), JSString::HasOtherOwner)); | 
| 468 |     } | 
| 469 |  | 
| 470 |     inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) | 
| 471 |     { | 
| 472 |         int size = s.size(); | 
| 473 |         if (!size) | 
| 474 |             return globalData->smallStrings.emptyString(globalData); | 
| 475 |         if (size == 1) { | 
| 476 |             UChar c = s.data()[0]; | 
| 477 |             if (c <= 0xFF) | 
| 478 |                 return globalData->smallStrings.singleCharacterString(globalData, character: c); | 
| 479 |         } | 
| 480 |         return fixupVPtr(globalData, string: new (globalData) JSString(globalData, s, JSString::HasOtherOwner)); | 
| 481 |     } | 
| 482 |  | 
| 483 |     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(globalData: &exec->globalData()); } | 
| 484 |     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(globalData: &exec->globalData(), s); } | 
| 485 |     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(globalData: &exec->globalData(), c); } | 
| 486 |     inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(globalData: &exec->globalData(), s, offset); } | 
| 487 |     inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(globalData: &exec->globalData(), s, offset, length); } | 
| 488 |     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(globalData: &exec->globalData(), s); } | 
| 489 |     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(globalData: &exec->globalData(), s); } | 
| 490 |     inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(globalData: &exec->globalData(), s); }  | 
| 491 |  | 
| 492 |     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | 
| 493 |     { | 
| 494 |         if (propertyName == exec->propertyNames().length) { | 
| 495 |             slot.setValue(jsNumber(exec, i: m_stringLength)); | 
| 496 |             return true; | 
| 497 |         } | 
| 498 |  | 
| 499 |         bool isStrictUInt32; | 
| 500 |         unsigned i = propertyName.toStrictUInt32(ok: &isStrictUInt32); | 
| 501 |         if (isStrictUInt32 && i < m_stringLength) { | 
| 502 |             slot.setValue(jsSingleCharacterSubstring(exec, s: value(exec), offset: i)); | 
| 503 |             return true; | 
| 504 |         } | 
| 505 |  | 
| 506 |         return false; | 
| 507 |     } | 
| 508 |          | 
| 509 |     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) | 
| 510 |     { | 
| 511 |         if (propertyName < m_stringLength) { | 
| 512 |             slot.setValue(jsSingleCharacterSubstring(exec, s: value(exec), offset: propertyName)); | 
| 513 |             return true; | 
| 514 |         } | 
| 515 |  | 
| 516 |         return false; | 
| 517 |     } | 
| 518 |  | 
| 519 |     inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; } | 
| 520 |  | 
| 521 |     // --- JSValue inlines ---------------------------- | 
| 522 |  | 
| 523 |     inline JSString* JSValue::toThisJSString(ExecState* exec) | 
| 524 |     { | 
| 525 |         return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, s: toString(exec)); | 
| 526 |     } | 
| 527 |  | 
| 528 |     inline UString JSValue::toString(ExecState* exec) const | 
| 529 |     { | 
| 530 |         if (isString()) | 
| 531 |             return static_cast<JSString*>(asCell())->value(exec); | 
| 532 |         if (isInt32()) | 
| 533 |             return exec->globalData().numericStrings.add(i: asInt32()); | 
| 534 |         if (isDouble()) | 
| 535 |             return exec->globalData().numericStrings.add(d: asDouble()); | 
| 536 |         if (isTrue()) | 
| 537 |             return "true" ; | 
| 538 |         if (isFalse()) | 
| 539 |             return "false" ; | 
| 540 |         if (isNull()) | 
| 541 |             return "null" ; | 
| 542 |         if (isUndefined()) | 
| 543 |             return "undefined" ; | 
| 544 |         ASSERT(isCell()); | 
| 545 |         return asCell()->toString(exec); | 
| 546 |     } | 
| 547 |  | 
| 548 |     inline UString JSValue::toPrimitiveString(ExecState* exec) const | 
| 549 |     { | 
| 550 |         if (isString()) | 
| 551 |             return static_cast<JSString*>(asCell())->value(exec); | 
| 552 |         if (isInt32()) | 
| 553 |             return exec->globalData().numericStrings.add(i: asInt32()); | 
| 554 |         if (isDouble()) | 
| 555 |             return exec->globalData().numericStrings.add(d: asDouble()); | 
| 556 |         if (isTrue()) | 
| 557 |             return "true" ; | 
| 558 |         if (isFalse()) | 
| 559 |             return "false" ; | 
| 560 |         if (isNull()) | 
| 561 |             return "null" ; | 
| 562 |         if (isUndefined()) | 
| 563 |             return "undefined" ; | 
| 564 |         ASSERT(isCell()); | 
| 565 |         return asCell()->toPrimitive(exec, NoPreference).toString(exec); | 
| 566 |     } | 
| 567 |  | 
| 568 | } // namespace JSC | 
| 569 |  | 
| 570 | #endif // JSString_h | 
| 571 |  |