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

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

Reviewed by Geoffrey Garen.

https://bugs.webkit.org/show_bug.cgi?id=33057
REGRESSION(r49365): typeof(xhr.responseText) != "string" in Windows

<rdar://problem/7296920> REGRESSION: WebKit fails to start PeaceKeeper benchmark

Test: fast/js/webcore-string-comparison.html

In r49365, some code was moved from JSString.cpp to JSString.h, and as a result, WebCore
got a way to directly instantiate JSStrings over DLL borders. Since vftable for JSString was
not exported, objects created from WebCore got a different vptr, and JavaScriptCore
optimizations that relied on vptr of all JSString objects being equal failed.

  • config.h: Added a JS_EXPORTCLASS macro for exporting classes. It's currently the same as JS_EXPORTDATA, but it clearly needed a new name.
  • runtime/InitializeThreading.cpp: (JSC::initializeThreadingOnce):
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::storeVPtrs): (JSC::JSGlobalData::JSGlobalData): (JSC::JSGlobalData::createNonDefault): (JSC::JSGlobalData::create): (JSC::JSGlobalData::sharedInstance):
  • runtime/JSGlobalData.h: Store vptrs just once, no need to repeatedly pick and copy them. This makes it possible to assert vptr correctness in object destructors (which don't have access to JSGlobalData, and even Heap::heap(this) will fail for fake objects created from storeVPtrs()).
  • runtime/JSArray.cpp: (JSC::JSArray::~JSArray): Assert that vptr is what we expect it to be. It's important to assert in destructor, because MSVC changes the vptr after constructor is invoked.
  • runtime/JSByteArray.cpp: (JSC::JSByteArray::~JSByteArray): Ditto.
  • runtime/JSByteArray.h: Ditto.
  • runtime/JSFunction.h: Ditto.
  • runtime/JSFunction.cpp: (JSC::JSFunction::~JSFunction): Ditto.
  • runtime/JSCell.h: (JSC::JSCell::setVPtr): Added a method to substitute vptr for another one.
  • runtime/JSString.h: Export JSString class together with its vftable, and tell other libraries tp import it. This is needed on platforms that have a separate JavaScriptCore dynamic library - and on Mac, we already did the export via JavaScriptCore.exp. (JSC::JSString::~JSString): Assert tha vptr is what we expect it to be. (JSC::fixupVPtr): Store a previously saved primary vftable pointer (do nothing if building JavaScriptCore itself). (JSC::jsSingleCharacterString): Call fixupVPtr in case this is call across DLL boundary. (JSC::jsSingleCharacterSubstring): Ditto. (JSC::jsNontrivialString): Ditto. (JSC::jsString): Ditto. (JSC::jsSubstring): Ditto. (JSC::jsOwnedString): Ditto.
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Export the new static JSGlobalData members that are used in WebCore via inline functions.
  • Property svn:eol-style set to native
File size: 21.9 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 class JS_EXPORTCLASS JSString : public JSCell {
63 public:
64 friend class JIT;
65 friend class JSGlobalData;
66
67 // A Rope is a string composed of a set of substrings.
68 class Rope : public RefCounted<Rope> {
69 public:
70 // A Rope is composed from a set of smaller strings called Fibers.
71 // Each Fiber in a rope is either UString::Rep or another Rope.
72 class Fiber {
73 public:
74 Fiber() {}
75 Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {}
76 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {}
77
78 void deref()
79 {
80 if (isRope())
81 rope()->deref();
82 else
83 string()->deref();
84 }
85
86 Fiber& ref()
87 {
88 if (isString())
89 string()->ref();
90 else
91 rope()->ref();
92 return *this;
93 }
94
95 unsigned refAndGetLength()
96 {
97 if (isString()) {
98 UString::Rep* rep = string();
99 return rep->ref()->size();
100 } else {
101 Rope* r = rope();
102 r->ref();
103 return r->stringLength();
104 }
105 }
106
107 bool isRope() { return m_value & 1; }
108 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); }
109 bool isString() { return !isRope(); }
110 UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); }
111
112 private:
113 intptr_t m_value;
114 };
115
116 // Creates a Rope comprising of 'ropeLength' Fibers.
117 // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope.
118 static PassRefPtr<Rope> createOrNull(unsigned ropeLength)
119 {
120 void* allocation;
121 if (tryFastMalloc(sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(allocation))
122 return adoptRef(new (allocation) Rope(ropeLength));
123 return 0;
124 }
125
126 ~Rope();
127 void destructNonRecursive();
128
129 void append(unsigned &index, Fiber& fiber)
130 {
131 m_fibers[index++] = fiber;
132 m_stringLength += fiber.refAndGetLength();
133 }
134 void append(unsigned &index, const UString& string)
135 {
136 UString::Rep* rep = string.rep();
137 m_fibers[index++] = Fiber(rep);
138 m_stringLength += rep->ref()->size();
139 }
140 void append(unsigned& index, JSString* jsString)
141 {
142 if (jsString->isRope()) {
143 for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
144 append(index, jsString->m_fibers[i]);
145 } else
146 append(index, jsString->string());
147 }
148
149 unsigned ropeLength() { return m_ropeLength; }
150 unsigned stringLength() { return m_stringLength; }
151 Fiber& fibers(unsigned index) { return m_fibers[index]; }
152
153 private:
154 Rope(unsigned ropeLength) : m_ropeLength(ropeLength), m_stringLength(0) {}
155 void* operator new(size_t, void* inPlace) { return inPlace; }
156
157 unsigned m_ropeLength;
158 unsigned m_stringLength;
159 Fiber m_fibers[1];
160 };
161
162 JSString(JSGlobalData* globalData, const UString& value)
163 : JSCell(globalData->stringStructure.get())
164 , m_stringLength(value.size())
165 , m_value(value)
166 , m_ropeLength(0)
167 {
168 Heap::heap(this)->reportExtraMemoryCost(value.cost());
169 }
170
171 enum HasOtherOwnerType { HasOtherOwner };
172 JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
173 : JSCell(globalData->stringStructure.get())
174 , m_stringLength(value.size())
175 , m_value(value)
176 , m_ropeLength(0)
177 {
178 }
179 JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
180 : JSCell(globalData->stringStructure.get())
181 , m_stringLength(value->size())
182 , m_value(value)
183 , m_ropeLength(0)
184 {
185 }
186 JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope)
187 : JSCell(globalData->stringStructure.get())
188 , m_stringLength(rope->stringLength())
189 , m_ropeLength(1)
190 {
191 m_fibers[0] = rope.releaseRef();
192 }
193 // This constructor constructs a new string by concatenating s1 & s2.
194 // This should only be called with ropeLength <= 3.
195 JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2)
196 : JSCell(globalData->stringStructure.get())
197 , m_stringLength(s1->length() + s2->length())
198 , m_ropeLength(ropeLength)
199 {
200 ASSERT(ropeLength <= s_maxInternalRopeLength);
201 unsigned index = 0;
202 appendStringInConstruct(index, s1);
203 appendStringInConstruct(index, s2);
204 ASSERT(ropeLength == index);
205 }
206 // This constructor constructs a new string by concatenating s1 & s2.
207 // This should only be called with ropeLength <= 3.
208 JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, const UString& u2)
209 : JSCell(globalData->stringStructure.get())
210 , m_stringLength(s1->length() + u2.size())
211 , m_ropeLength(ropeLength)
212 {
213 ASSERT(ropeLength <= s_maxInternalRopeLength);
214 unsigned index = 0;
215 appendStringInConstruct(index, s1);
216 appendStringInConstruct(index, u2);
217 ASSERT(ropeLength == index);
218 }
219 // This constructor constructs a new string by concatenating s1 & s2.
220 // This should only be called with ropeLength <= 3.
221 JSString(JSGlobalData* globalData, unsigned ropeLength, const UString& u1, JSString* s2)
222 : JSCell(globalData->stringStructure.get())
223 , m_stringLength(u1.size() + s2->length())
224 , m_ropeLength(ropeLength)
225 {
226 ASSERT(ropeLength <= s_maxInternalRopeLength);
227 unsigned index = 0;
228 appendStringInConstruct(index, u1);
229 appendStringInConstruct(index, s2);
230 ASSERT(ropeLength == index);
231 }
232 // This constructor constructs a new string by concatenating v1, v2 & v3.
233 // This should only be called with ropeLength <= 3 ... which since every
234 // value must require a ropeLength of at least one implies that the length
235 // for each value must be exactly 1!
236 JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
237 : JSCell(exec->globalData().stringStructure.get())
238 , m_stringLength(0)
239 , m_ropeLength(s_maxInternalRopeLength)
240 {
241 unsigned index = 0;
242 appendValueInConstructAndIncrementLength(exec, index, v1);
243 appendValueInConstructAndIncrementLength(exec, index, v2);
244 appendValueInConstructAndIncrementLength(exec, index, v3);
245 ASSERT(index == s_maxInternalRopeLength);
246 }
247
248 ~JSString()
249 {
250 ASSERT(vptr() == JSGlobalData::jsStringVPtr);
251 for (unsigned i = 0; i < m_ropeLength; ++i)
252 m_fibers[i].deref();
253 }
254
255 const UString& value(ExecState* exec) const
256 {
257 if (isRope())
258 resolveRope(exec);
259 return m_value;
260 }
261 const UString tryGetValue() const
262 {
263 if (isRope())
264 UString();
265 return m_value;
266 }
267 unsigned length() { return m_stringLength; }
268
269 bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
270 bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
271 bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
272
273 bool canGetIndex(unsigned i) { return i < m_stringLength; }
274 JSString* getIndex(ExecState*, unsigned);
275
276 static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); }
277
278 private:
279 enum VPtrStealingHackType { VPtrStealingHack };
280 JSString(VPtrStealingHackType)
281 : JSCell(0)
282 , m_ropeLength(0)
283 {
284 }
285
286 void resolveRope(ExecState*) const;
287
288 void appendStringInConstruct(unsigned& index, const UString& string)
289 {
290 m_fibers[index++] = Rope::Fiber(string.rep()->ref());
291 }
292
293 void appendStringInConstruct(unsigned& index, JSString* jsString)
294 {
295 if (jsString->isRope()) {
296 for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
297 m_fibers[index++] = jsString->m_fibers[i].ref();
298 } else
299 appendStringInConstruct(index, jsString->string());
300 }
301
302 void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
303 {
304 if (v.isString()) {
305 ASSERT(asCell(v)->isString());
306 JSString* s = static_cast<JSString*>(asCell(v));
307 ASSERT(s->ropeLength() == 1);
308 appendStringInConstruct(index, s);
309 m_stringLength += s->length();
310 } else {
311 UString u(v.toString(exec));
312 m_fibers[index++] = Rope::Fiber(u.rep()->ref());
313 m_stringLength += u.size();
314 }
315 }
316
317 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
318 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
319 virtual bool toBoolean(ExecState*) const;
320 virtual double toNumber(ExecState*) const;
321 virtual JSObject* toObject(ExecState*) const;
322 virtual UString toString(ExecState*) const;
323
324 virtual JSObject* toThisObject(ExecState*) const;
325 virtual UString toThisString(ExecState*) const;
326 virtual JSString* toThisJSString(ExecState*);
327
328 // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
329 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
330 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
331 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
332
333 static const unsigned s_maxInternalRopeLength = 3;
334
335 // A string is represented either by a UString or a Rope.
336 unsigned m_stringLength;
337 mutable UString m_value;
338 mutable unsigned m_ropeLength;
339 mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
340
341 bool isRope() const { return m_ropeLength; }
342 UString& string() { ASSERT(!isRope()); return m_value; }
343 unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; }
344
345 friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
346 friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
347 friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
348 friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
349 friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
350 };
351
352 JSString* asString(JSValue);
353
354 // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
355 // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
356 // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
357 // The below function must be called by any inline function that invokes a JSString constructor.
358#if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
359 inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
360#else
361 inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
362#endif
363
364 inline JSString* asString(JSValue value)
365 {
366 ASSERT(asCell(value)->isString());
367 return static_cast<JSString*>(asCell(value));
368 }
369
370 inline JSString* jsEmptyString(JSGlobalData* globalData)
371 {
372 return globalData->smallStrings.emptyString(globalData);
373 }
374
375 inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
376 {
377 if (c <= 0xFF)
378 return globalData->smallStrings.singleCharacterString(globalData, c);
379 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
380 }
381
382 inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset)
383 {
384 ASSERT(offset < static_cast<unsigned>(s.size()));
385 UChar c = s.data()[offset];
386 if (c <= 0xFF)
387 return globalData->smallStrings.singleCharacterString(globalData, c);
388 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))));
389 }
390
391 inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
392 {
393 ASSERT(s);
394 ASSERT(s[0]);
395 ASSERT(s[1]);
396 return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
397 }
398
399 inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
400 {
401 ASSERT(s.size() > 1);
402 return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
403 }
404
405 inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
406 {
407 ASSERT(canGetIndex(i));
408 return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i);
409 }
410
411 inline JSString* jsString(JSGlobalData* globalData, const UString& s)
412 {
413 int size = s.size();
414 if (!size)
415 return globalData->smallStrings.emptyString(globalData);
416 if (size == 1) {
417 UChar c = s.data()[0];
418 if (c <= 0xFF)
419 return globalData->smallStrings.singleCharacterString(globalData, c);
420 }
421 return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
422 }
423
424 inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
425 {
426 ASSERT(offset <= static_cast<unsigned>(s.size()));
427 ASSERT(length <= static_cast<unsigned>(s.size()));
428 ASSERT(offset + length <= static_cast<unsigned>(s.size()));
429 if (!length)
430 return globalData->smallStrings.emptyString(globalData);
431 if (length == 1) {
432 UChar c = s.data()[offset];
433 if (c <= 0xFF)
434 return globalData->smallStrings.singleCharacterString(globalData, c);
435 }
436 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner));
437 }
438
439 inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
440 {
441 int size = s.size();
442 if (!size)
443 return globalData->smallStrings.emptyString(globalData);
444 if (size == 1) {
445 UChar c = s.data()[0];
446 if (c <= 0xFF)
447 return globalData->smallStrings.singleCharacterString(globalData, c);
448 }
449 return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
450 }
451
452 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
453 inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
454 inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
455 inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); }
456 inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
457 inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
458 inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
459 inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); }
460
461 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
462 {
463 if (propertyName == exec->propertyNames().length) {
464 slot.setValue(jsNumber(exec, m_stringLength));
465 return true;
466 }
467
468 bool isStrictUInt32;
469 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
470 if (isStrictUInt32 && i < m_stringLength) {
471 slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i));
472 return true;
473 }
474
475 return false;
476 }
477
478 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
479 {
480 if (propertyName < m_stringLength) {
481 slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName));
482 return true;
483 }
484
485 return false;
486 }
487
488 inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
489
490 // --- JSValue inlines ----------------------------
491
492 inline JSString* JSValue::toThisJSString(ExecState* exec)
493 {
494 return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec));
495 }
496
497 inline UString JSValue::toString(ExecState* exec) const
498 {
499 if (isString())
500 return static_cast<JSString*>(asCell())->value(exec);
501 if (isInt32())
502 return exec->globalData().numericStrings.add(asInt32());
503 if (isDouble())
504 return exec->globalData().numericStrings.add(asDouble());
505 if (isTrue())
506 return "true";
507 if (isFalse())
508 return "false";
509 if (isNull())
510 return "null";
511 if (isUndefined())
512 return "undefined";
513 ASSERT(isCell());
514 return asCell()->toString(exec);
515 }
516
517 inline UString JSValue::toPrimitiveString(ExecState* exec) const
518 {
519 if (isString())
520 return static_cast<JSString*>(asCell())->value(exec);
521 if (isInt32())
522 return exec->globalData().numericStrings.add(asInt32());
523 if (isDouble())
524 return exec->globalData().numericStrings.add(asDouble());
525 if (isTrue())
526 return "true";
527 if (isFalse())
528 return "false";
529 if (isNull())
530 return "null";
531 if (isUndefined())
532 return "undefined";
533 ASSERT(isCell());
534 return asCell()->toPrimitive(exec, NoPreference).toString(exec);
535 }
536
537} // namespace JSC
538
539#endif // JSString_h
Note: See TracBrowser for help on using the repository browser.