source: webkit/trunk/JavaScriptCore/runtime/JSString.h@ 53371

Last change on this file since 53371 was 53371, checked in by [email protected], 15 years ago

2010-01-16 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

Cache JS string values made from DOM strings (Dromaeo speedup)
https://bugs.webkit.org/show_bug.cgi?id=33768
<rdar://problem/7353576>

  • runtime/JSString.h: (JSC::jsStringWithFinalizer): Added new mechanism for a string to have an optional finalizer callback, for the benefit of weak-referencing caches. (JSC::): (JSC::Fiber::JSString): (JSC::Fiber::~JSString):
  • runtime/JSString.cpp: (JSC::JSString::resolveRope): Clear fibers so this doesn't look like a string with a finalizer.
  • runtime/WeakGCMap.h: Include "Collector.h" to make this header includable by itself.

2010-01-16 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

Cache JS string values made from DOM strings (Dromaeo speedup)
https://bugs.webkit.org/show_bug.cgi?id=33768
<rdar://problem/7353576>


  • Plugins/Hosted/ProxyInstance.mm: (WebKit::ProxyInstance::stringValue): Explicitly make a String, since char* is now ambiguous.

2010-01-16 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

Cache JS string values made from DOM strings (Dromaeo speedup)
https://bugs.webkit.org/show_bug.cgi?id=33768
<rdar://problem/7353576>

Added a new cache for JSString values that are created from Strings or AtomicStrings
in the DOM. It's common for the same string to be retrieved from the DOM repeatedly,
and it is wasteful to make a new JS-level string value every time.


The string cache is per-world, and thus thread-safe and not a
vector for accidental information exchange.


~30% speedup on Dromaeo Attributes test, also substantially helps other Dromaeo DOM tests.

  • bindings/js/JSDOMBinding.cpp: (WebCore::jsStringCache): Helper function to get the string cache for the current world. (WebCore::jsString): Some new overloads including the caching version. (WebCore::stringWrapperDestroyed): Finalizer callback - remove from relevant caches.
  • bindings/js/JSDOMBinding.h: (WebCore::jsString): Prototype new overloads (and define a few inline).
  • bindings/js/JSJavaScriptCallFrameCustom.cpp: (WebCore::JSJavaScriptCallFrame::type): Explicitly make a UString.
  • bindings/js/ScriptFunctionCall.cpp: (WebCore::ScriptFunctionCall::appendArgument): Ditto.
  • WebCore.base.exp: Add new JSString overloads that WebCore gets to see.
  • Property svn:eol-style set to native
File size: 23.5 KB
Line 
1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
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
33namespace 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(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
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, jsString->m_fibers[i]);
151 } else
152 append(index, 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 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 };
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, 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.
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.
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!
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
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*>(finalizer);
262 m_fibers[1] = context;
263 Heap::heap(this)->reportExtraMemoryCost(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 = reinterpret_cast<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(proto, 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, 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(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
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, c);
403 return fixupVPtr(globalData, 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, c);
412 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 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, 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, new (globalData) JSString(globalData, s));
427 }
428
429 inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
430 {
431 ASSERT(canGetIndex(i));
432 return jsSingleCharacterSubstring(&exec->globalData(), value(exec), 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, c);
444 }
445 return fixupVPtr(globalData, 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, 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, c);
466 }
467 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(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, c);
479 }
480 return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
481 }
482
483 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
484 inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
485 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
486 inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); }
487 inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
488 inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
489 inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
490 inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&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, 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
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
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, 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(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
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
Note: See TracBrowser for help on using the repository browser.