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

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

2010-04-26 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Need to support more efficient dispatch of lightweight builtins
https://bugs.webkit.org/show_bug.cgi?id=38155

The problem with calling lightweight builtins is that marshalling
the call from the nitro calling convention to the system calling
convention is very expensive relative to the cost of the actually
evaluating the function. To work around this problem this patch
adds the ability to define a custom thunk for a builtin.

This allows us to use high performance custom implementations of
the common and sensible versions of simple builtins. This patch
includes a simple (use of which is currently hardcoded) thunk for
charCodeAt.

This adds a JSInterfaceJIT subclass called SpecializedThunkJIT
that has helper functions to remove (or at least reduce) the need
to have separate thunk implementations for each JSValue encoding.

  • create_hash_table: Add thunk generation callbacks to the hash tables, currently we hardcode the script to only support charCodeAt
  • jit/JITStubCall.h:
  • jit/JITStubs.cpp: (JSC::JITThunks::~JITThunks): (JSC::JITThunks::specializedThunk):
  • jit/JITStubs.h:
  • jit/SpecializedThunkJIT.h: Added. (JSC::SpecializedThunkJIT::SpecializedThunkJIT): (JSC::SpecializedThunkJIT::loadCellArgument): (JSC::SpecializedThunkJIT::loadJSStringArgument): (JSC::SpecializedThunkJIT::loadInt32Argument): (JSC::SpecializedThunkJIT::appendFailure): (JSC::SpecializedThunkJIT::returnInt32): (JSC::SpecializedThunkJIT::finalize): (JSC::SpecializedThunkJIT::argumentToVirtualRegister): (JSC::SpecializedThunkJIT::tagReturnAsInt32):
  • jit/ThunkGenerators.cpp: Added. (JSC::ThunkHelpers::stringImplDataOffset): (JSC::ThunkHelpers::jsStringLengthOffset): (JSC::ThunkHelpers::jsStringValueOffset): (JSC::charCodeAtThunkGenerator):
  • jit/ThunkGenerators.h: Added.
  • runtime/Executable.h: (JSC::NativeExecutable::NativeExecutable):
  • runtime/JSFunction.cpp: (JSC::JSFunction::JSFunction):
  • runtime/JSFunction.h:
  • runtime/JSGlobalData.h: (JSC::JSGlobalData::getThunk):
  • runtime/JSString.h: (JSC::):
  • runtime/JSValue.h: Protect some of the JSVALUE32 and JSVALUE32_64 only constants and function behind appropriate USE() guards to make it harder to use the wrong flags for the target build.
  • runtime/Lookup.cpp: (JSC::HashTable::createTable): (JSC::setUpStaticFunctionSlot):
  • runtime/Lookup.h: (JSC::HashEntry::initialize): (JSC::HashEntry::generator): (JSC::HashEntry::): Make the lookup tables use a specialized thunkGenerator if present
  • wtf/text/StringImpl.h:

2010-04-26 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Need to support more efficient dispatch of lightweight builtins
https://bugs.webkit.org/show_bug.cgi?id=38155

Update bindings generation to include new thunk generator field
in the property map hash tables.

  • bindings/scripts/CodeGeneratorJS.pm:
  • Property svn:eol-style set to native
File size: 21.4 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#include "RopeImpl.h"
33
34namespace JSC {
35
36 class JSString;
37
38 JSString* jsEmptyString(JSGlobalData*);
39 JSString* jsEmptyString(ExecState*);
40 JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string
41 JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string
42
43 JSString* jsSingleCharacterString(JSGlobalData*, UChar);
44 JSString* jsSingleCharacterString(ExecState*, UChar);
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 friend class SpecializedThunkJIT;
70 friend struct ThunkHelpers;
71
72 class RopeBuilder {
73 public:
74 RopeBuilder(unsigned fiberCount)
75 : m_index(0)
76 , m_rope(RopeImpl::tryCreateUninitialized(fiberCount))
77 {
78 }
79
80 bool isOutOfMemory() { return !m_rope; }
81
82 void append(RopeImpl::Fiber& fiber)
83 {
84 ASSERT(m_rope);
85 m_rope->initializeFiber(m_index, fiber);
86 }
87 void append(const UString& string)
88 {
89 ASSERT(m_rope);
90 m_rope->initializeFiber(m_index, string.rep());
91 }
92 void append(JSString* jsString)
93 {
94 if (jsString->isRope()) {
95 for (unsigned i = 0; i < jsString->m_fiberCount; ++i)
96 append(jsString->m_other.m_fibers[i]);
97 } else
98 append(jsString->string());
99 }
100
101 PassRefPtr<RopeImpl> release()
102 {
103 ASSERT(m_index == m_rope->fiberCount());
104 return m_rope.release();
105 }
106
107 unsigned length() { return m_rope->length(); }
108
109 private:
110 unsigned m_index;
111 RefPtr<RopeImpl> m_rope;
112 };
113
114 ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value)
115 : JSCell(globalData->stringStructure.get())
116 , m_length(value.size())
117 , m_value(value)
118 , m_fiberCount(0)
119 {
120 ASSERT(!m_value.isNull());
121 Heap::heap(this)->reportExtraMemoryCost(value.cost());
122 }
123
124 enum HasOtherOwnerType { HasOtherOwner };
125 JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
126 : JSCell(globalData->stringStructure.get())
127 , m_length(value.size())
128 , m_value(value)
129 , m_fiberCount(0)
130 {
131 ASSERT(!m_value.isNull());
132 }
133 JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
134 : JSCell(globalData->stringStructure.get())
135 , m_length(value->length())
136 , m_value(value)
137 , m_fiberCount(0)
138 {
139 ASSERT(!m_value.isNull());
140 }
141 JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope)
142 : JSCell(globalData->stringStructure.get())
143 , m_length(rope->length())
144 , m_fiberCount(1)
145 {
146 m_other.m_fibers[0] = rope.releaseRef();
147 }
148 // This constructor constructs a new string by concatenating s1 & s2.
149 // This should only be called with fiberCount <= 3.
150 JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, JSString* s2)
151 : JSCell(globalData->stringStructure.get())
152 , m_length(s1->length() + s2->length())
153 , m_fiberCount(fiberCount)
154 {
155 ASSERT(fiberCount <= s_maxInternalRopeLength);
156 unsigned index = 0;
157 appendStringInConstruct(index, s1);
158 appendStringInConstruct(index, s2);
159 ASSERT(fiberCount == index);
160 }
161 // This constructor constructs a new string by concatenating s1 & s2.
162 // This should only be called with fiberCount <= 3.
163 JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, const UString& u2)
164 : JSCell(globalData->stringStructure.get())
165 , m_length(s1->length() + u2.size())
166 , m_fiberCount(fiberCount)
167 {
168 ASSERT(fiberCount <= s_maxInternalRopeLength);
169 unsigned index = 0;
170 appendStringInConstruct(index, s1);
171 appendStringInConstruct(index, u2);
172 ASSERT(fiberCount == index);
173 }
174 // This constructor constructs a new string by concatenating s1 & s2.
175 // This should only be called with fiberCount <= 3.
176 JSString(JSGlobalData* globalData, unsigned fiberCount, const UString& u1, JSString* s2)
177 : JSCell(globalData->stringStructure.get())
178 , m_length(u1.size() + s2->length())
179 , m_fiberCount(fiberCount)
180 {
181 ASSERT(fiberCount <= s_maxInternalRopeLength);
182 unsigned index = 0;
183 appendStringInConstruct(index, u1);
184 appendStringInConstruct(index, s2);
185 ASSERT(fiberCount == index);
186 }
187 // This constructor constructs a new string by concatenating v1, v2 & v3.
188 // This should only be called with fiberCount <= 3 ... which since every
189 // value must require a fiberCount of at least one implies that the length
190 // for each value must be exactly 1!
191 JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
192 : JSCell(exec->globalData().stringStructure.get())
193 , m_length(0)
194 , m_fiberCount(s_maxInternalRopeLength)
195 {
196 unsigned index = 0;
197 appendValueInConstructAndIncrementLength(exec, index, v1);
198 appendValueInConstructAndIncrementLength(exec, index, v2);
199 appendValueInConstructAndIncrementLength(exec, index, v3);
200 ASSERT(index == s_maxInternalRopeLength);
201 }
202
203 JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context)
204 : JSCell(globalData->stringStructure.get())
205 , m_length(value.size())
206 , m_value(value)
207 , m_fiberCount(0)
208 {
209 ASSERT(!m_value.isNull());
210 // nasty hack because we can't union non-POD types
211 m_other.m_finalizerCallback = finalizer;
212 m_other.m_finalizerContext = context;
213 Heap::heap(this)->reportExtraMemoryCost(value.cost());
214 }
215
216 ~JSString()
217 {
218 ASSERT(vptr() == JSGlobalData::jsStringVPtr);
219 for (unsigned i = 0; i < m_fiberCount; ++i)
220 RopeImpl::deref(m_other.m_fibers[i]);
221
222 if (!m_fiberCount && m_other.m_finalizerCallback)
223 m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
224 }
225
226 const UString& value(ExecState* exec) const
227 {
228 if (isRope())
229 resolveRope(exec);
230 return m_value;
231 }
232 const UString tryGetValue() const
233 {
234 // If this is a rope, m_value should be null -
235 // if this is not a rope, m_value should be non-null.
236 ASSERT(isRope() == m_value.isNull());
237 return m_value;
238 }
239 unsigned length() { return m_length; }
240
241 bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
242 bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
243 bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
244
245 bool canGetIndex(unsigned i) { return i < m_length; }
246 JSString* getIndex(ExecState*, unsigned);
247 JSString* getIndexSlowCase(ExecState*, unsigned);
248
249 static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
250
251 private:
252 enum VPtrStealingHackType { VPtrStealingHack };
253 JSString(VPtrStealingHackType)
254 : JSCell(0)
255 , m_fiberCount(0)
256 {
257 }
258
259 void resolveRope(ExecState*) const;
260
261 void appendStringInConstruct(unsigned& index, const UString& string)
262 {
263 UStringImpl* impl = string.rep();
264 impl->ref();
265 m_other.m_fibers[index++] = impl;
266 }
267
268 void appendStringInConstruct(unsigned& index, JSString* jsString)
269 {
270 if (jsString->isRope()) {
271 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {
272 RopeImpl::Fiber fiber = jsString->m_other.m_fibers[i];
273 fiber->ref();
274 m_other.m_fibers[index++] = fiber;
275 }
276 } else
277 appendStringInConstruct(index, jsString->string());
278 }
279
280 void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
281 {
282 if (v.isString()) {
283 ASSERT(asCell(v)->isString());
284 JSString* s = static_cast<JSString*>(asCell(v));
285 ASSERT(s->fiberCount() == 1);
286 appendStringInConstruct(index, s);
287 m_length += s->length();
288 } else {
289 UString u(v.toString(exec));
290 UStringImpl* impl = u.rep();
291 impl->ref();
292 m_other.m_fibers[index++] = impl;
293 m_length += u.size();
294 }
295 }
296
297 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
298 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
299 virtual bool toBoolean(ExecState*) const;
300 virtual double toNumber(ExecState*) const;
301 virtual JSObject* toObject(ExecState*) const;
302 virtual UString toString(ExecState*) const;
303
304 virtual JSObject* toThisObject(ExecState*) const;
305
306 // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
307 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
308 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
309 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
310
311 static const unsigned s_maxInternalRopeLength = 3;
312
313 // A string is represented either by a UString or a RopeImpl.
314 unsigned m_length;
315 mutable UString m_value;
316 mutable unsigned m_fiberCount;
317 // This structure exists to support a temporary workaround for a GC issue.
318 struct JSStringFinalizerStruct {
319 JSStringFinalizerStruct() : m_finalizerCallback(0) {}
320 union {
321 mutable RopeImpl::Fiber m_fibers[s_maxInternalRopeLength];
322 struct {
323 JSStringFinalizerCallback m_finalizerCallback;
324 void* m_finalizerContext;
325 };
326 };
327 } m_other;
328
329 bool isRope() const { return m_fiberCount; }
330 UString& string() { ASSERT(!isRope()); return m_value; }
331 unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; }
332
333 friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
334 friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
335 friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
336 friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
337 friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
338 friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
339 };
340
341 JSString* asString(JSValue);
342
343 // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
344 // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
345 // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
346 // The below function must be called by any inline function that invokes a JSString constructor.
347#if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
348 inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
349#else
350 inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
351#endif
352
353 inline JSString* asString(JSValue value)
354 {
355 ASSERT(asCell(value)->isString());
356 return static_cast<JSString*>(asCell(value));
357 }
358
359 inline JSString* jsEmptyString(JSGlobalData* globalData)
360 {
361 return globalData->smallStrings.emptyString(globalData);
362 }
363
364 inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
365 {
366 if (c <= 0xFF)
367 return globalData->smallStrings.singleCharacterString(globalData, c);
368 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
369 }
370
371 inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
372 {
373 JSGlobalData* globalData = &exec->globalData();
374 ASSERT(offset < static_cast<unsigned>(s.size()));
375 UChar c = s.data()[offset];
376 if (c <= 0xFF)
377 return globalData->smallStrings.singleCharacterString(globalData, c);
378 return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))));
379 }
380
381 inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
382 {
383 ASSERT(s);
384 ASSERT(s[0]);
385 ASSERT(s[1]);
386 return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
387 }
388
389 inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
390 {
391 ASSERT(s.size() > 1);
392 return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
393 }
394
395 inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
396 {
397 ASSERT(canGetIndex(i));
398 if (isRope())
399 return getIndexSlowCase(exec, i);
400 ASSERT(i < m_value.size());
401 return jsSingleCharacterSubstring(exec, value(exec), i);
402 }
403
404 inline JSString* jsString(JSGlobalData* globalData, const UString& s)
405 {
406 int size = s.size();
407 if (!size)
408 return globalData->smallStrings.emptyString(globalData);
409 if (size == 1) {
410 UChar c = s.data()[0];
411 if (c <= 0xFF)
412 return globalData->smallStrings.singleCharacterString(globalData, c);
413 }
414 return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
415 }
416
417 inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
418 {
419 ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF));
420 JSGlobalData* globalData = &exec->globalData();
421 return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
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* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
456 inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
457 inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }
458 inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); }
459
460 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
461 {
462 if (propertyName == exec->propertyNames().length) {
463 slot.setValue(jsNumber(exec, m_length));
464 return true;
465 }
466
467 bool isStrictUInt32;
468 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
469 if (isStrictUInt32 && i < m_length) {
470 slot.setValue(getIndex(exec, i));
471 return true;
472 }
473
474 return false;
475 }
476
477 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
478 {
479 if (propertyName < m_length) {
480 slot.setValue(getIndex(exec, propertyName));
481 return true;
482 }
483
484 return false;
485 }
486
487 inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; }
488
489 // --- JSValue inlines ----------------------------
490
491 inline UString JSValue::toString(ExecState* exec) const
492 {
493 if (isString())
494 return static_cast<JSString*>(asCell())->value(exec);
495 if (isInt32())
496 return exec->globalData().numericStrings.add(asInt32());
497 if (isDouble())
498 return exec->globalData().numericStrings.add(asDouble());
499 if (isTrue())
500 return "true";
501 if (isFalse())
502 return "false";
503 if (isNull())
504 return "null";
505 if (isUndefined())
506 return "undefined";
507 ASSERT(isCell());
508 return asCell()->toString(exec);
509 }
510
511 inline UString JSValue::toPrimitiveString(ExecState* exec) const
512 {
513 if (isString())
514 return static_cast<JSString*>(asCell())->value(exec);
515 if (isInt32())
516 return exec->globalData().numericStrings.add(asInt32());
517 if (isDouble())
518 return exec->globalData().numericStrings.add(asDouble());
519 if (isTrue())
520 return "true";
521 if (isFalse())
522 return "false";
523 if (isNull())
524 return "null";
525 if (isUndefined())
526 return "undefined";
527 ASSERT(isCell());
528 return asCell()->toPrimitive(exec, NoPreference).toString(exec);
529 }
530
531} // namespace JSC
532
533#endif // JSString_h
Note: See TracBrowser for help on using the repository browser.