Changeset 153239 in webkit for trunk/Source/JavaScriptCore/runtime/JSString.h
- Timestamp:
- Jul 24, 2013, 9:03:27 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/runtime/JSString.h
r153225 r153239 32 32 namespace JSC { 33 33 34 class JSString; 35 class JSRopeString; 36 class LLIntOffsetsExtractor; 37 38 JSString* jsEmptyString(VM*); 39 JSString* jsEmptyString(ExecState*); 40 JSString* jsString(VM*, const String&); // returns empty string if passed null string 41 JSString* jsString(ExecState*, const String&); // returns empty string if passed null string 42 43 JSString* jsSingleCharacterString(VM*, UChar); 44 JSString* jsSingleCharacterString(ExecState*, UChar); 45 JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset); 46 JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length); 47 JSString* jsSubstring(ExecState*, const String&, 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(VM*, const String&); 52 JSString* jsNontrivialString(ExecState*, const String&); 53 54 // Should be used for strings that are owned by an object that will 55 // likely outlive the JSValue this makes, such as the parse tree or a 56 // DOM object that contains a String 57 JSString* jsOwnedString(VM*, const String&); 58 JSString* jsOwnedString(ExecState*, const String&); 59 60 JSRopeString* jsStringBuilder(VM*); 61 62 class JSString : public JSCell { 63 public: 64 friend class JIT; 65 friend class VM; 66 friend class SpecializedThunkJIT; 67 friend class JSRopeString; 68 friend class MarkStack; 69 friend class SlotVisitor; 70 friend struct ThunkHelpers; 71 72 typedef JSCell Base; 73 74 static const bool needsDestruction = true; 75 static const bool hasImmortalStructure = true; 76 static void destroy(JSCell*); 77 78 private: 79 JSString(VM& vm, PassRefPtr<StringImpl> value) 80 : JSCell(vm, vm.stringStructure.get()) 81 , m_flags(0) 82 , m_value(value) 83 { 84 } 85 86 JSString(VM& vm) 87 : JSCell(vm, vm.stringStructure.get()) 88 , m_flags(0) 89 { 90 } 91 92 void finishCreation(VM& vm, size_t length) 93 { 94 ASSERT(!m_value.isNull()); 95 Base::finishCreation(vm); 96 m_length = length; 97 setIs8Bit(m_value.impl()->is8Bit()); 98 vm.m_newStringsSinceLastHashCons++; 99 } 100 101 void finishCreation(VM& vm, size_t length, size_t cost) 102 { 103 ASSERT(!m_value.isNull()); 104 Base::finishCreation(vm); 105 m_length = length; 106 setIs8Bit(m_value.impl()->is8Bit()); 107 Heap::heap(this)->reportExtraMemoryCost(cost); 108 vm.m_newStringsSinceLastHashCons++; 109 } 110 111 protected: 112 void finishCreation(VM& vm) 113 { 114 Base::finishCreation(vm); 115 m_length = 0; 116 setIs8Bit(true); 117 vm.m_newStringsSinceLastHashCons++; 118 } 119 120 public: 121 static JSString* create(VM& vm, PassRefPtr<StringImpl> value) 122 { 123 ASSERT(value); 124 size_t length = value->length(); 125 size_t cost = value->cost(); 126 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); 127 newString->finishCreation(vm, length, cost); 128 return newString; 129 } 130 static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value) 131 { 132 ASSERT(value); 133 size_t length = value->length(); 134 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); 135 newString->finishCreation(vm, length); 136 return newString; 137 } 138 139 const String& value(ExecState*) const; 140 const String& tryGetValue() const; 141 const StringImpl* tryGetValueImpl() const; 142 unsigned length() { return m_length; } 143 144 JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; 145 JS_EXPORT_PRIVATE bool toBoolean() const; 146 bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; 147 JSObject* toObject(ExecState*, JSGlobalObject*) const; 148 double toNumber(ExecState*) const; 149 150 bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&); 151 bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 152 bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); 153 154 bool canGetIndex(unsigned i) { return i < m_length; } 155 JSString* getIndex(ExecState*, unsigned); 156 157 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) 158 { 159 return Structure::create(vm, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), &s_info); 160 } 161 162 static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } 163 static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); } 164 static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } 165 166 static JS_EXPORTDATA const ClassInfo s_info; 167 168 static void visitChildren(JSCell*, SlotVisitor&); 169 170 enum { 171 HashConsLock = 1u << 2, 172 IsHashConsSingleton = 1u << 1, 173 Is8Bit = 1u 34 class JSString; 35 class JSRopeString; 36 class LLIntOffsetsExtractor; 37 38 JSString* jsEmptyString(VM*); 39 JSString* jsEmptyString(ExecState*); 40 JSString* jsString(VM*, const String&); // returns empty string if passed null string 41 JSString* jsString(ExecState*, const String&); // returns empty string if passed null string 42 43 JSString* jsSingleCharacterString(VM*, UChar); 44 JSString* jsSingleCharacterString(ExecState*, UChar); 45 JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset); 46 JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length); 47 JSString* jsSubstring(ExecState*, const String&, 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(VM*, const String&); 52 JSString* jsNontrivialString(ExecState*, const String&); 53 54 // Should be used for strings that are owned by an object that will 55 // likely outlive the JSValue this makes, such as the parse tree or a 56 // DOM object that contains a String 57 JSString* jsOwnedString(VM*, const String&); 58 JSString* jsOwnedString(ExecState*, const String&); 59 60 JSRopeString* jsStringBuilder(VM*); 61 62 class JSString : public JSCell { 63 public: 64 friend class JIT; 65 friend class VM; 66 friend class SpecializedThunkJIT; 67 friend class JSRopeString; 68 friend class MarkStack; 69 friend class SlotVisitor; 70 friend struct ThunkHelpers; 71 72 typedef JSCell Base; 73 74 static const bool needsDestruction = true; 75 static const bool hasImmortalStructure = true; 76 static void destroy(JSCell*); 77 78 private: 79 JSString(VM& vm, PassRefPtr<StringImpl> value) 80 : JSCell(vm, vm.stringStructure.get()) 81 , m_flags(0) 82 , m_value(value) 83 { 84 } 85 86 JSString(VM& vm) 87 : JSCell(vm, vm.stringStructure.get()) 88 , m_flags(0) 89 { 90 } 91 92 void finishCreation(VM& vm, size_t length) 93 { 94 ASSERT(!m_value.isNull()); 95 Base::finishCreation(vm); 96 m_length = length; 97 setIs8Bit(m_value.impl()->is8Bit()); 98 vm.m_newStringsSinceLastHashCons++; 99 } 100 101 void finishCreation(VM& vm, size_t length, size_t cost) 102 { 103 ASSERT(!m_value.isNull()); 104 Base::finishCreation(vm); 105 m_length = length; 106 setIs8Bit(m_value.impl()->is8Bit()); 107 Heap::heap(this)->reportExtraMemoryCost(cost); 108 vm.m_newStringsSinceLastHashCons++; 109 } 110 111 protected: 112 void finishCreation(VM& vm) 113 { 114 Base::finishCreation(vm); 115 m_length = 0; 116 setIs8Bit(true); 117 vm.m_newStringsSinceLastHashCons++; 118 } 119 120 public: 121 static JSString* create(VM& vm, PassRefPtr<StringImpl> value) 122 { 123 ASSERT(value); 124 size_t length = value->length(); 125 size_t cost = value->cost(); 126 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); 127 newString->finishCreation(vm, length, cost); 128 return newString; 129 } 130 static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value) 131 { 132 ASSERT(value); 133 size_t length = value->length(); 134 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); 135 newString->finishCreation(vm, length); 136 return newString; 137 } 138 139 const String& value(ExecState*) const; 140 const String& tryGetValue() const; 141 const StringImpl* tryGetValueImpl() const; 142 unsigned length() { return m_length; } 143 144 JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; 145 JS_EXPORT_PRIVATE bool toBoolean() const; 146 bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; 147 JSObject* toObject(ExecState*, JSGlobalObject*) const; 148 double toNumber(ExecState*) const; 149 150 bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&); 151 bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 152 bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); 153 154 bool canGetIndex(unsigned i) { return i < m_length; } 155 JSString* getIndex(ExecState*, unsigned); 156 157 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) 158 { 159 return Structure::create(vm, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), &s_info); 160 } 161 162 static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } 163 static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); } 164 static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } 165 166 static JS_EXPORTDATA const ClassInfo s_info; 167 168 static void visitChildren(JSCell*, SlotVisitor&); 169 170 enum { 171 HashConsLock = 1u << 2, 172 IsHashConsSingleton = 1u << 1, 173 Is8Bit = 1u 174 }; 175 176 protected: 177 friend class JSValue; 178 179 bool isRope() const { return m_value.isNull(); } 180 bool is8Bit() const { return m_flags & Is8Bit; } 181 void setIs8Bit(bool flag) 182 { 183 if (flag) 184 m_flags |= Is8Bit; 185 else 186 m_flags &= ~Is8Bit; 187 } 188 bool shouldTryHashCons(); 189 bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; } 190 void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; } 191 void setHashConsSingleton() { m_flags |= IsHashConsSingleton; } 192 bool tryHashConsLock(); 193 void releaseHashConsLock(); 194 195 unsigned m_flags; 196 197 // A string is represented either by a String or a rope of fibers. 198 unsigned m_length; 199 mutable String m_value; 200 201 private: 202 friend class LLIntOffsetsExtractor; 203 204 static JSValue toThis(JSCell*, ExecState*, ECMAMode); 205 206 // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). 207 static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); 208 static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); 209 210 String& string() { ASSERT(!isRope()); return m_value; } 211 212 friend JSValue jsString(ExecState*, JSString*, JSString*); 213 friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); 174 214 }; 175 215 176 protected: 177 friend class JSValue; 178 179 bool isRope() const { return m_value.isNull(); } 180 bool is8Bit() const { return m_flags & Is8Bit; } 181 void setIs8Bit(bool flag) 182 { 183 if (flag) 184 m_flags |= Is8Bit; 185 else 186 m_flags &= ~Is8Bit; 187 } 188 bool shouldTryHashCons(); 189 bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; } 190 void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; } 191 void setHashConsSingleton() { m_flags |= IsHashConsSingleton; } 192 bool tryHashConsLock(); 193 void releaseHashConsLock(); 194 195 unsigned m_flags; 196 197 // A string is represented either by a String or a rope of fibers. 198 unsigned m_length; 199 mutable String m_value; 200 201 private: 202 friend class LLIntOffsetsExtractor; 203 204 static JSValue toThis(JSCell*, ExecState*, ECMAMode); 205 206 // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). 207 static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); 208 static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); 209 210 String& string() { ASSERT(!isRope()); return m_value; } 211 212 friend JSValue jsString(ExecState*, JSString*, JSString*); 213 friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); 214 }; 215 216 class JSRopeString : public JSString { 217 friend class JSString; 218 219 friend JSRopeString* jsStringBuilder(VM*); 220 221 class RopeBuilder { 216 class JSRopeString : public JSString { 217 friend class JSString; 218 219 friend JSRopeString* jsStringBuilder(VM*); 220 221 class RopeBuilder { 222 public: 223 RopeBuilder(VM& vm) 224 : m_vm(vm) 225 , m_jsString(jsStringBuilder(&vm)) 226 , m_index(0) 227 { 228 } 229 230 void append(JSString* jsString) 231 { 232 if (m_index == JSRopeString::s_maxInternalRopeLength) 233 expand(); 234 m_jsString->append(m_vm, m_index++, jsString); 235 } 236 237 JSRopeString* release() 238 { 239 JSRopeString* tmp = m_jsString; 240 m_jsString = 0; 241 return tmp; 242 } 243 244 unsigned length() { return m_jsString->m_length; } 245 246 private: 247 void expand(); 248 249 VM& m_vm; 250 JSRopeString* m_jsString; 251 size_t m_index; 252 }; 253 254 private: 255 JSRopeString(VM& vm) 256 : JSString(vm) 257 { 258 } 259 260 void finishCreation(VM& vm, JSString* s1, JSString* s2) 261 { 262 Base::finishCreation(vm); 263 m_length = s1->length() + s2->length(); 264 setIs8Bit(s1->is8Bit() && s2->is8Bit()); 265 m_fibers[0].set(vm, this, s1); 266 m_fibers[1].set(vm, this, s2); 267 } 268 269 void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) 270 { 271 Base::finishCreation(vm); 272 m_length = s1->length() + s2->length() + s3->length(); 273 setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); 274 m_fibers[0].set(vm, this, s1); 275 m_fibers[1].set(vm, this, s2); 276 m_fibers[2].set(vm, this, s3); 277 } 278 279 void finishCreation(VM& vm) 280 { 281 JSString::finishCreation(vm); 282 } 283 284 void append(VM& vm, size_t index, JSString* jsString) 285 { 286 m_fibers[index].set(vm, this, jsString); 287 m_length += jsString->m_length; 288 setIs8Bit(is8Bit() && jsString->is8Bit()); 289 } 290 291 static JSRopeString* createNull(VM& vm) 292 { 293 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 294 newString->finishCreation(vm); 295 return newString; 296 } 297 222 298 public: 223 RopeBuilder(VM& vm) 224 : m_vm(vm) 225 , m_jsString(jsStringBuilder(&vm)) 226 , m_index(0) 227 { 228 } 229 230 void append(JSString* jsString) 231 { 232 if (m_index == JSRopeString::s_maxInternalRopeLength) 233 expand(); 234 m_jsString->append(m_vm, m_index++, jsString); 235 } 236 237 JSRopeString* release() 238 { 239 JSRopeString* tmp = m_jsString; 240 m_jsString = 0; 241 return tmp; 242 } 243 244 unsigned length() { return m_jsString->m_length; } 245 299 static JSString* create(VM& vm, JSString* s1, JSString* s2) 300 { 301 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 302 newString->finishCreation(vm, s1, s2); 303 return newString; 304 } 305 static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) 306 { 307 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 308 newString->finishCreation(vm, s1, s2, s3); 309 return newString; 310 } 311 312 void visitFibers(SlotVisitor&); 313 314 static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); } 315 316 static const unsigned s_maxInternalRopeLength = 3; 317 246 318 private: 247 void expand(); 248 249 VM& m_vm; 250 JSRopeString* m_jsString; 251 size_t m_index; 319 friend JSValue jsString(ExecState*, Register*, unsigned); 320 friend JSValue jsStringFromArguments(ExecState*, JSValue); 321 322 JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; 323 void resolveRopeSlowCase8(LChar*) const; 324 void resolveRopeSlowCase(UChar*) const; 325 void outOfMemory(ExecState*) const; 326 327 JSString* getIndexSlowCase(ExecState*, unsigned); 328 329 mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers; 252 330 }; 253 254 private: 255 JSRopeString(VM& vm) 256 : JSString(vm) 257 { 258 } 259 260 void finishCreation(VM& vm, JSString* s1, JSString* s2) 261 { 262 Base::finishCreation(vm); 263 m_length = s1->length() + s2->length(); 264 setIs8Bit(s1->is8Bit() && s2->is8Bit()); 265 m_fibers[0].set(vm, this, s1); 266 m_fibers[1].set(vm, this, s2); 267 } 268 269 void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) 270 { 271 Base::finishCreation(vm); 272 m_length = s1->length() + s2->length() + s3->length(); 273 setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); 274 m_fibers[0].set(vm, this, s1); 275 m_fibers[1].set(vm, this, s2); 276 m_fibers[2].set(vm, this, s3); 277 } 278 279 void finishCreation(VM& vm) 280 { 281 JSString::finishCreation(vm); 282 } 283 284 void append(VM& vm, size_t index, JSString* jsString) 285 { 286 m_fibers[index].set(vm, this, jsString); 287 m_length += jsString->m_length; 288 setIs8Bit(is8Bit() && jsString->is8Bit()); 289 } 290 291 static JSRopeString* createNull(VM& vm) 292 { 293 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 294 newString->finishCreation(vm); 295 return newString; 296 } 297 298 public: 299 static JSString* create(VM& vm, JSString* s1, JSString* s2) 300 { 301 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 302 newString->finishCreation(vm, s1, s2); 303 return newString; 304 } 305 static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) 306 { 307 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 308 newString->finishCreation(vm, s1, s2, s3); 309 return newString; 310 } 311 312 void visitFibers(SlotVisitor&); 313 314 static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); } 315 316 static const unsigned s_maxInternalRopeLength = 3; 317 318 private: 319 friend JSValue jsString(ExecState*, Register*, unsigned); 320 friend JSValue jsStringFromArguments(ExecState*, JSValue); 321 322 JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; 323 void resolveRopeSlowCase8(LChar*) const; 324 void resolveRopeSlowCase(UChar*) const; 325 void outOfMemory(ExecState*) const; 326 327 JSString* getIndexSlowCase(ExecState*, unsigned); 328 329 mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers; 330 }; 331 332 333 inline const StringImpl* JSString::tryGetValueImpl() const 334 { 335 return m_value.impl(); 336 } 337 338 JSString* asString(JSValue); 339 340 inline JSString* asString(JSValue value) 341 { 342 ASSERT(value.asCell()->isString()); 343 return jsCast<JSString*>(value.asCell()); 344 } 345 346 inline JSString* jsEmptyString(VM* vm) 347 { 348 return vm->smallStrings.emptyString(); 349 } 350 351 ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c) 352 { 353 if (c <= maxSingleCharacterString) 354 return vm->smallStrings.singleCharacterString(vm, c); 355 return JSString::create(*vm, String(&c, 1).impl()); 356 } 357 358 ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset) 359 { 360 VM* vm = &exec->vm(); 361 ASSERT(offset < static_cast<unsigned>(s.length())); 362 UChar c = s.characterAt(offset); 363 if (c <= maxSingleCharacterString) 364 return vm->smallStrings.singleCharacterString(vm, c); 365 return JSString::create(*vm, StringImpl::create(s.impl(), offset, 1)); 366 } 367 368 inline JSString* jsNontrivialString(VM* vm, const String& s) 369 { 370 ASSERT(s.length() > 1); 371 return JSString::create(*vm, s.impl()); 372 } 373 374 inline const String& JSString::value(ExecState* exec) const 375 { 376 if (isRope()) 377 static_cast<const JSRopeString*>(this)->resolveRope(exec); 378 return m_value; 379 } 380 381 inline const String& JSString::tryGetValue() const 382 { 383 if (isRope()) 384 static_cast<const JSRopeString*>(this)->resolveRope(0); 385 return m_value; 386 } 387 388 inline JSString* JSString::getIndex(ExecState* exec, unsigned i) 389 { 390 ASSERT(canGetIndex(i)); 391 if (isRope()) 392 return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i); 393 ASSERT(i < m_value.length()); 394 return jsSingleCharacterSubstring(exec, m_value, i); 395 } 396 397 inline JSString* jsString(VM* vm, const String& s) 398 { 399 int size = s.length(); 400 if (!size) 331 332 333 inline const StringImpl* JSString::tryGetValueImpl() const 334 { 335 return m_value.impl(); 336 } 337 338 JSString* asString(JSValue); 339 340 inline JSString* asString(JSValue value) 341 { 342 ASSERT(value.asCell()->isString()); 343 return jsCast<JSString*>(value.asCell()); 344 } 345 346 inline JSString* jsEmptyString(VM* vm) 347 { 401 348 return vm->smallStrings.emptyString(); 402 if (size == 1) { 403 UChar c = s.characterAt(0); 349 } 350 351 ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c) 352 { 404 353 if (c <= maxSingleCharacterString) 405 354 return vm->smallStrings.singleCharacterString(vm, c); 406 } 407 return JSString::create(*vm, s.impl()); 408 } 409 410 inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) 411 { 412 ASSERT(offset <= static_cast<unsigned>(s->length())); 413 ASSERT(length <= static_cast<unsigned>(s->length())); 414 ASSERT(offset + length <= static_cast<unsigned>(s->length())); 415 VM* vm = &exec->vm(); 416 if (!length) 417 return vm->smallStrings.emptyString(); 418 return jsSubstring(vm, s->value(exec), offset, length); 419 } 420 421 inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length) 422 { 423 ASSERT(offset <= static_cast<unsigned>(s.length())); 424 ASSERT(length <= static_cast<unsigned>(s.length())); 425 ASSERT(offset + length <= static_cast<unsigned>(s.length())); 426 if (!length) 427 return vm->smallStrings.emptyString(); 428 if (length == 1) { 355 return JSString::create(*vm, String(&c, 1).impl()); 356 } 357 358 ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset) 359 { 360 VM* vm = &exec->vm(); 361 ASSERT(offset < static_cast<unsigned>(s.length())); 429 362 UChar c = s.characterAt(offset); 430 363 if (c <= maxSingleCharacterString) 431 364 return vm->smallStrings.singleCharacterString(vm, c); 432 } 433 return JSString::createHasOtherOwner(*vm, StringImpl::create8(s.impl(), offset, length)); 434 } 435 436 inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length) 437 { 438 ASSERT(offset <= static_cast<unsigned>(s.length())); 439 ASSERT(length <= static_cast<unsigned>(s.length())); 440 ASSERT(offset + length <= static_cast<unsigned>(s.length())); 441 if (!length) 442 return vm->smallStrings.emptyString(); 443 if (length == 1) { 444 UChar c = s.characterAt(offset); 445 if (c <= maxSingleCharacterString) 446 return vm->smallStrings.singleCharacterString(vm, c); 447 } 448 return JSString::createHasOtherOwner(*vm, StringImpl::create(s.impl(), offset, length)); 449 } 450 451 inline JSString* jsOwnedString(VM* vm, const String& s) 452 { 453 int size = s.length(); 454 if (!size) 455 return vm->smallStrings.emptyString(); 456 if (size == 1) { 457 UChar c = s.characterAt(0); 458 if (c <= maxSingleCharacterString) 459 return vm->smallStrings.singleCharacterString(vm, c); 460 } 461 return JSString::createHasOtherOwner(*vm, s.impl()); 462 } 463 464 inline JSRopeString* jsStringBuilder(VM* vm) 465 { 466 return JSRopeString::createNull(*vm); 467 } 468 469 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); } 470 inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); } 471 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); } 472 inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); } 473 inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); } 474 inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); } 475 inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); } 476 477 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) 478 { 479 if (propertyName == exec->propertyNames().length) { 480 slot.setValue(jsNumber(m_length)); 481 return true; 482 } 483 484 unsigned i = propertyName.asIndex(); 485 if (i < m_length) { 486 ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! 487 slot.setValue(getIndex(exec, i)); 488 return true; 489 } 490 491 return false; 492 } 365 return JSString::create(*vm, StringImpl::create(s.impl(), offset, 1)); 366 } 367 368 inline JSString* jsNontrivialString(VM* vm, const String& s) 369 { 370 ASSERT(s.length() > 1); 371 return JSString::create(*vm, s.impl()); 372 } 373 374 inline const String& JSString::value(ExecState* exec) const 375 { 376 if (isRope()) 377 static_cast<const JSRopeString*>(this)->resolveRope(exec); 378 return m_value; 379 } 380 381 inline const String& JSString::tryGetValue() const 382 { 383 if (isRope()) 384 static_cast<const JSRopeString*>(this)->resolveRope(0); 385 return m_value; 386 } 387 388 inline JSString* JSString::getIndex(ExecState* exec, unsigned i) 389 { 390 ASSERT(canGetIndex(i)); 391 if (isRope()) 392 return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i); 393 ASSERT(i < m_value.length()); 394 return jsSingleCharacterSubstring(exec, m_value, i); 395 } 396 397 inline JSString* jsString(VM* vm, const String& s) 398 { 399 int size = s.length(); 400 if (!size) 401 return vm->smallStrings.emptyString(); 402 if (size == 1) { 403 UChar c = s.characterAt(0); 404 if (c <= maxSingleCharacterString) 405 return vm->smallStrings.singleCharacterString(vm, c); 406 } 407 return JSString::create(*vm, s.impl()); 408 } 409 410 inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) 411 { 412 ASSERT(offset <= static_cast<unsigned>(s->length())); 413 ASSERT(length <= static_cast<unsigned>(s->length())); 414 ASSERT(offset + length <= static_cast<unsigned>(s->length())); 415 VM* vm = &exec->vm(); 416 if (!length) 417 return vm->smallStrings.emptyString(); 418 return jsSubstring(vm, s->value(exec), offset, length); 419 } 420 421 inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length) 422 { 423 ASSERT(offset <= static_cast<unsigned>(s.length())); 424 ASSERT(length <= static_cast<unsigned>(s.length())); 425 ASSERT(offset + length <= static_cast<unsigned>(s.length())); 426 if (!length) 427 return vm->smallStrings.emptyString(); 428 if (length == 1) { 429 UChar c = s.characterAt(offset); 430 if (c <= maxSingleCharacterString) 431 return vm->smallStrings.singleCharacterString(vm, c); 432 } 433 return JSString::createHasOtherOwner(*vm, StringImpl::create8(s.impl(), offset, length)); 434 } 435 436 inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length) 437 { 438 ASSERT(offset <= static_cast<unsigned>(s.length())); 439 ASSERT(length <= static_cast<unsigned>(s.length())); 440 ASSERT(offset + length <= static_cast<unsigned>(s.length())); 441 if (!length) 442 return vm->smallStrings.emptyString(); 443 if (length == 1) { 444 UChar c = s.characterAt(offset); 445 if (c <= maxSingleCharacterString) 446 return vm->smallStrings.singleCharacterString(vm, c); 447 } 448 return JSString::createHasOtherOwner(*vm, StringImpl::create(s.impl(), offset, length)); 449 } 450 451 inline JSString* jsOwnedString(VM* vm, const String& s) 452 { 453 int size = s.length(); 454 if (!size) 455 return vm->smallStrings.emptyString(); 456 if (size == 1) { 457 UChar c = s.characterAt(0); 458 if (c <= maxSingleCharacterString) 459 return vm->smallStrings.singleCharacterString(vm, c); 460 } 461 return JSString::createHasOtherOwner(*vm, s.impl()); 462 } 463 464 inline JSRopeString* jsStringBuilder(VM* vm) 465 { 466 return JSRopeString::createNull(*vm); 467 } 468 469 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); } 470 inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); } 471 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); } 472 inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); } 473 inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); } 474 inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); } 475 inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); } 476 477 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) 478 { 479 if (propertyName == exec->propertyNames().length) { 480 slot.setValue(jsNumber(m_length)); 481 return true; 482 } 483 484 unsigned i = propertyName.asIndex(); 485 if (i < m_length) { 486 ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! 487 slot.setValue(getIndex(exec, i)); 488 return true; 489 } 490 491 return false; 492 } 493 494 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) 495 { 496 if (propertyName < m_length) { 497 slot.setValue(getIndex(exec, propertyName)); 498 return true; 499 } 500 501 return false; 502 } 503 504 inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSString::s_info; } 505 506 // --- JSValue inlines ---------------------------- 493 507 494 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) 495 { 496 if (propertyName < m_length) { 497 slot.setValue(getIndex(exec, propertyName)); 498 return true; 499 } 500 501 return false; 502 } 503 504 inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSString::s_info; } 505 506 // --- JSValue inlines ---------------------------- 507 508 inline bool JSValue::toBoolean(ExecState* exec) const 509 { 510 if (isInt32()) 511 return asInt32(); 512 if (isDouble()) 513 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN 514 if (isCell()) 515 return asCell()->toBoolean(exec); 516 return isTrue(); // false, null, and undefined all convert to false. 517 } 518 519 inline JSString* JSValue::toString(ExecState* exec) const 520 { 521 if (isString()) 522 return jsCast<JSString*>(asCell()); 523 return toStringSlowCase(exec); 524 } 525 526 inline String JSValue::toWTFString(ExecState* exec) const 527 { 528 if (isString()) 529 return static_cast<JSString*>(asCell())->value(exec); 530 return toWTFStringSlowCase(exec); 531 } 532 533 ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec) 534 { 535 VM& vm = exec->vm(); 536 if (value.isInt32()) 537 return vm.numericStrings.add(value.asInt32()); 538 if (value.isDouble()) 539 return vm.numericStrings.add(value.asDouble()); 540 if (value.isTrue()) 541 return vm.propertyNames->trueKeyword.string(); 542 if (value.isFalse()) 543 return vm.propertyNames->falseKeyword.string(); 544 if (value.isNull()) 545 return vm.propertyNames->nullKeyword.string(); 546 if (value.isUndefined()) 547 return vm.propertyNames->undefinedKeyword.string(); 548 return value.toString(exec)->value(exec); 549 } 550 551 ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const 552 { 553 if (isString()) 554 return static_cast<JSString*>(asCell())->value(exec); 555 556 return inlineJSValueNotStringtoString(*this, exec); 557 } 508 inline bool JSValue::toBoolean(ExecState* exec) const 509 { 510 if (isInt32()) 511 return asInt32(); 512 if (isDouble()) 513 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN 514 if (isCell()) 515 return asCell()->toBoolean(exec); 516 return isTrue(); // false, null, and undefined all convert to false. 517 } 518 519 inline JSString* JSValue::toString(ExecState* exec) const 520 { 521 if (isString()) 522 return jsCast<JSString*>(asCell()); 523 return toStringSlowCase(exec); 524 } 525 526 inline String JSValue::toWTFString(ExecState* exec) const 527 { 528 if (isString()) 529 return static_cast<JSString*>(asCell())->value(exec); 530 return toWTFStringSlowCase(exec); 531 } 532 533 ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec) 534 { 535 VM& vm = exec->vm(); 536 if (value.isInt32()) 537 return vm.numericStrings.add(value.asInt32()); 538 if (value.isDouble()) 539 return vm.numericStrings.add(value.asDouble()); 540 if (value.isTrue()) 541 return vm.propertyNames->trueKeyword.string(); 542 if (value.isFalse()) 543 return vm.propertyNames->falseKeyword.string(); 544 if (value.isNull()) 545 return vm.propertyNames->nullKeyword.string(); 546 if (value.isUndefined()) 547 return vm.propertyNames->undefinedKeyword.string(); 548 return value.toString(exec)->value(exec); 549 } 550 551 ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const 552 { 553 if (isString()) 554 return static_cast<JSString*>(asCell())->value(exec); 555 556 return inlineJSValueNotStringtoString(*this, exec); 557 } 558 558 559 559 } // namespace JSC
Note:
See TracChangeset
for help on using the changeset viewer.