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: Fiber()77 Fiber() : m_value(0) {} Fiber(UString::Rep * string)78 Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {} Fiber(Rope * rope)79 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {} 80 Fiber(void * nonFiber)81 Fiber(void* nonFiber) : m_value(reinterpret_cast<intptr_t>(nonFiber)) {} 82 deref()83 void deref() 84 { 85 if (isRope()) 86 rope()->deref(); 87 else 88 string()->deref(); 89 } 90 ref()91 Fiber& ref() 92 { 93 if (isString()) 94 string()->ref(); 95 else 96 rope()->ref(); 97 return *this; 98 } 99 refAndGetLength()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 isRope()112 bool isRope() { return m_value & 1; } rope()113 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); } isString()114 bool isString() { return !isRope(); } string()115 UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); } 116 nonFiber()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. createOrNull(unsigned ropeLength)124 static PassRefPtr<Rope> createOrNull(unsigned ropeLength) 125 { 126 void* allocation; 127 if (tryFastMalloc(sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(allocation)) 128 return adoptRef(new (allocation) Rope(ropeLength)); 129 return 0; 130 } 131 132 ~Rope(); 133 void destructNonRecursive(); 134 append(unsigned & index,Fiber & fiber)135 void append(unsigned &index, Fiber& fiber) 136 { 137 m_fibers[index++] = fiber; 138 m_stringLength += fiber.refAndGetLength(); 139 } append(unsigned & index,const UString & string)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 } append(unsigned & index,JSString * jsString)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, jsString->m_fibers[i]); 151 } else 152 append(index, jsString->string()); 153 } 154 ropeLength()155 unsigned ropeLength() { return m_ropeLength; } stringLength()156 unsigned stringLength() { return m_stringLength; } fibers(unsigned index)157 Fiber& fibers(unsigned index) { return m_fibers[index]; } 158 159 private: Rope(unsigned ropeLength)160 Rope(unsigned ropeLength) : m_ropeLength(ropeLength), m_stringLength(0) {} new(size_t,void * inPlace)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 JSString(JSGlobalData * globalData,const UString & value)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(this)->reportExtraMemoryCost(value.cost()); 175 } 176 177 enum HasOtherOwnerType { HasOtherOwner }; JSString(JSGlobalData * globalData,const UString & value,HasOtherOwnerType)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 } JSString(JSGlobalData * globalData,PassRefPtr<UString::Rep> value,HasOtherOwnerType)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 } JSString(JSGlobalData * globalData,PassRefPtr<JSString::Rope> rope)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. JSString(JSGlobalData * globalData,unsigned ropeLength,JSString * s1,JSString * s2)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, s1); 209 appendStringInConstruct(index, 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. JSString(JSGlobalData * globalData,unsigned ropeLength,JSString * s1,const UString & u2)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, s1); 222 appendStringInConstruct(index, 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. JSString(JSGlobalData * globalData,unsigned ropeLength,const UString & u1,JSString * s2)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, u1); 235 appendStringInConstruct(index, 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! JSString(ExecState * exec,JSValue v1,JSValue v2,JSValue v3)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, v1); 249 appendValueInConstructAndIncrementLength(exec, index, v2); 250 appendValueInConstructAndIncrementLength(exec, index, v3); 251 ASSERT(index == s_maxInternalRopeLength); 252 } 253 JSString(JSGlobalData * globalData,const UString & value,JSStringFinalizerCallback finalizer,void * context)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(this)->reportExtraMemoryCost(value.cost()); 264 } 265 ~JSString()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 value(ExecState * exec)278 const UString& value(ExecState* exec) const 279 { 280 if (isRope()) 281 resolveRope(exec); 282 return m_value; 283 } tryGetValue()284 const UString tryGetValue() const 285 { 286 if (isRope()) 287 UString(); 288 return m_value; 289 } length()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 canGetIndex(unsigned i)296 bool canGetIndex(unsigned i) { return i < m_stringLength; } 297 JSString* getIndex(ExecState*, unsigned); 298 createStructure(JSValue proto)299 static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); } 300 301 private: 302 enum VPtrStealingHackType { VPtrStealingHack }; JSString(VPtrStealingHackType)303 JSString(VPtrStealingHackType) 304 : JSCell(0) 305 , m_ropeLength(0) 306 { 307 } 308 309 void resolveRope(ExecState*) const; 310 appendStringInConstruct(unsigned & index,const UString & string)311 void appendStringInConstruct(unsigned& index, const UString& string) 312 { 313 m_fibers[index++] = Rope::Fiber(string.rep()->ref()); 314 } 315 appendStringInConstruct(unsigned & index,JSString * jsString)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, jsString->string()); 323 } 324 appendValueInConstructAndIncrementLength(ExecState * exec,unsigned & index,JSValue v)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(v)); 330 ASSERT(s->ropeLength() == 1); 331 appendStringInConstruct(index, 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 isRope()364 bool isRope() const { return m_ropeLength; } string()365 UString& string() { ASSERT(!isRope()); return m_value; } ropeLength()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) fixupVPtr(JSGlobalData * globalData,JSString * string)383 inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; } 384 #else fixupVPtr(JSGlobalData *,JSString * string)385 inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; } 386 #endif 387 asString(JSValue value)388 inline JSString* asString(JSValue value) 389 { 390 ASSERT(asCell(value)->isString()); 391 return static_cast<JSString*>(asCell(value)); 392 } 393 jsEmptyString(JSGlobalData * globalData)394 inline JSString* jsEmptyString(JSGlobalData* globalData) 395 { 396 return globalData->smallStrings.emptyString(globalData); 397 } 398 jsSingleCharacterString(JSGlobalData * globalData,UChar c)399 inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) 400 { 401 if (c <= 0xFF) 402 return globalData->smallStrings.singleCharacterString(globalData, c); 403 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1))); 404 } 405 jsSingleCharacterSubstring(JSGlobalData * globalData,const UString & s,unsigned offset)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, c); 412 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1)))); 413 } 414 jsNontrivialString(JSGlobalData * globalData,const char * s)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, new (globalData) JSString(globalData, s)); 421 } 422 jsNontrivialString(JSGlobalData * globalData,const UString & s)423 inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s) 424 { 425 ASSERT(s.size() > 1); 426 return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); 427 } 428 getIndex(ExecState * exec,unsigned i)429 inline JSString* JSString::getIndex(ExecState* exec, unsigned i) 430 { 431 ASSERT(canGetIndex(i)); 432 return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i); 433 } 434 jsString(JSGlobalData * globalData,const UString & s)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, c); 444 } 445 return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); 446 } 447 jsStringWithFinalizer(ExecState * exec,const UString & s,JSStringFinalizerCallback callback,void * context)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, new (globalData) JSString(globalData, s, callback, context)); 453 } 454 jsSubstring(JSGlobalData * globalData,const UString & s,unsigned offset,unsigned length)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, c); 466 } 467 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner)); 468 } 469 jsOwnedString(JSGlobalData * globalData,const UString & s)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, c); 479 } 480 return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner)); 481 } 482 jsEmptyString(ExecState * exec)483 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } jsString(ExecState * exec,const UString & s)484 inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); } jsSingleCharacterString(ExecState * exec,UChar c)485 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); } jsSingleCharacterSubstring(ExecState * exec,const UString & s,unsigned offset)486 inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); } jsSubstring(ExecState * exec,const UString & s,unsigned offset,unsigned length)487 inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); } jsNontrivialString(ExecState * exec,const UString & s)488 inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); } jsNontrivialString(ExecState * exec,const char * s)489 inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); } jsOwnedString(ExecState * exec,const UString & s)490 inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); } 491 getStringPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)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, m_stringLength)); 496 return true; 497 } 498 499 bool isStrictUInt32; 500 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); 501 if (isStrictUInt32 && i < m_stringLength) { 502 slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i)); 503 return true; 504 } 505 506 return false; 507 } 508 getStringPropertySlot(ExecState * exec,unsigned propertyName,PropertySlot & slot)509 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) 510 { 511 if (propertyName < m_stringLength) { 512 slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName)); 513 return true; 514 } 515 516 return false; 517 } 518 isJSString(JSGlobalData * globalData,JSValue v)519 inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; } 520 521 // --- JSValue inlines ---------------------------- 522 toThisJSString(ExecState * exec)523 inline JSString* JSValue::toThisJSString(ExecState* exec) 524 { 525 return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec)); 526 } 527 toString(ExecState * exec)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(asInt32()); 534 if (isDouble()) 535 return exec->globalData().numericStrings.add(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 toPrimitiveString(ExecState * exec)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(asInt32()); 554 if (isDouble()) 555 return exec->globalData().numericStrings.add(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