2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2003, 2004, 2005, 2007 Apple Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include "JSImmediate.h"
29 #include "collector.h"
30 #include <wtf/Noncopyable.h>
31 #include <stddef.h> // for size_t
33 #ifndef NDEBUG // protection against problems if committing with KJS_VERBOSE on
35 // Uncomment this to enable very verbose output from KJS
37 // Uncomment this to debug memory allocation and garbage collection
38 //#define KJS_DEBUG_MEM
50 * JSValue is the base type for all primitives (Undefined, Null, Boolean,
51 * String, Number) and objects in ECMAScript.
53 * Note: you should never inherit from JSValue as it is for primitive types
54 * only (all of which are provided internally by KJS). Instead, inherit from
57 class KJS_EXPORT JSValue
: Noncopyable
{
58 friend class JSCell
; // so it can derive from this class
59 friend class Collector
; // so it can call asCell()
68 bool isUndefined() const;
70 bool isUndefinedOrNull() const;
71 bool isBoolean() const;
72 bool isNumber() const;
73 bool isString() const;
74 bool isObject() const;
75 bool isObject(const ClassInfo
*) const;
77 // Extracting the value.
78 bool getBoolean(bool&) const;
79 bool getBoolean() const; // false if not a boolean
80 bool getNumber(double&) const;
81 double getNumber() const; // NaN if not a number
82 bool getString(UString
&) const;
83 UString
getString() const; // null string if not a string
84 JSObject
*getObject(); // NULL if not an object
85 const JSObject
*getObject() const; // NULL if not an object
87 // Extracting integer values.
88 bool getUInt32(uint32_t&) const;
89 bool getTruncatedInt32(int32_t&) const;
90 bool getTruncatedUInt32(uint32_t&) const;
92 JSValue
* getByIndex(ExecState
* exec
, unsigned propertyName
) const;
95 JSValue
* toPrimitive(ExecState
* exec
, JSType preferredType
= UnspecifiedType
) const;
96 bool getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
*& value
);
98 bool toBoolean(ExecState
*exec
) const;
99 double toNumber(ExecState
*exec
) const;
100 JSValue
* toJSNumber(ExecState
*) const; // Fast path for when you expect that the value is an immediate number.
101 UString
toString(ExecState
*exec
) const;
102 JSObject
*toObject(ExecState
*exec
) const;
104 // Integer conversions.
105 double toInteger(ExecState
*) const;
106 double toIntegerPreserveNaN(ExecState
*) const;
107 int32_t toInt32(ExecState
*) const;
108 int32_t toInt32(ExecState
*, bool& ok
) const;
109 uint32_t toUInt32(ExecState
*) const;
110 uint32_t toUInt32(ExecState
*, bool& ok
) const;
111 uint16_t toUInt16(ExecState
*exec
) const;
113 // These are identical logic to above, and faster than jsNumber(number)->toInt32(exec)
114 static int32_t toInt32(double);
115 static int32_t toUInt32(double);
117 // Floating point conversions.
118 float toFloat(ExecState
*) const;
120 // Object-level properties...
123 * Whether or not the value implements the call() method. If it does, this also
124 * implies this is an object, and hence it can be cast to a JSObject
125 * and the call method can be invoked
127 * @return true if this is an object implementing the call() method, otherwise
130 bool implementsCall() const;
132 // Garbage collection.
136 static int32_t toInt32SlowCase(double, bool& ok
);
137 static uint32_t toUInt32SlowCase(double, bool& ok
);
140 int32_t toInt32SlowCase(ExecState
*, bool& ok
) const;
141 uint32_t toUInt32SlowCase(ExecState
*, bool& ok
) const;
143 // Implementation details.
145 const JSCell
*asCell() const;
147 // emulate Q_DISABLE_COPY to avoid msvc linker errors
148 #if !defined(_MSC_VER) || !defined(MAKE_KJS_LIB)
149 // Give a compile time error if we try to copy one of these.
150 JSValue(const JSValue
&);
151 JSValue
& operator=(const JSValue
&);
155 class KJS_EXPORT JSCell
: public JSValue
{
156 friend class Collector
;
157 friend class NumberImp
;
158 friend class StringImp
;
159 friend class JSObject
;
160 friend class GetterSetterImp
;
165 // Querying the type.
166 virtual JSType
type() const = 0;
167 bool isNumber() const;
168 bool isString() const;
169 bool isObject() const;
170 bool isObject(const ClassInfo
*) const;
172 // Extracting the value.
173 bool getNumber(double&) const;
174 double getNumber() const; // NaN if not a number
175 bool getString(UString
&) const;
176 UString
getString() const; // null string if not a string
177 JSObject
*getObject(); // NULL if not an object
178 const JSObject
*getObject() const; // NULL if not an object
180 // Extracting integer values.
181 virtual bool getUInt32(uint32_t&) const;
182 virtual bool getTruncatedInt32(int32_t&) const;
183 virtual bool getTruncatedUInt32(uint32_t&) const;
185 // Basic conversions.
186 virtual JSValue
*toPrimitive(ExecState
*exec
, JSType preferredType
= UnspecifiedType
) const = 0;
187 virtual bool getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
*& value
) = 0;
188 virtual bool toBoolean(ExecState
*exec
) const = 0;
189 virtual double toNumber(ExecState
*exec
) const = 0;
190 virtual UString
toString(ExecState
*exec
) const = 0;
191 virtual JSObject
*toObject(ExecState
*exec
) const = 0;
193 // Higher-level (object-like) properties:
194 virtual bool implementsCall() const;
196 // Garbage collection.
197 void *operator new(size_t);
202 KJS_EXPORT JSValue
*jsNumberCell(double);
204 KJS_EXPORT JSCell
* jsString(); // returns empty string
205 KJS_EXPORT JSCell
* jsString(const UString
&); // returns empty string if passed null string
206 KJS_EXPORT JSCell
* jsString(const char* = ""); // returns empty string if passed 0
207 KJS_EXPORT JSCell
* jsString(const char* s
, int len
);
209 // should be used for strings that are owned by an object that will
210 // likely outlive the JSValue this makes, such as the parse tree or a
211 // DOM object that contains a UString
212 JSCell
*jsOwnedString(const UString
&);
214 KJS_EXPORT
extern const double NaN
;
215 KJS_EXPORT
extern const double Inf
;
217 inline JSValue
* jsUndefined()
219 return JSImmediate::undefinedImmediate();
222 inline JSValue
* jsNull()
224 return JSImmediate::nullImmediate();
227 inline JSValue
* jsNaN()
232 } nan
= { 0x7ff80000ULL
<< 32 };
233 return jsNumberCell(nan
.d
);
236 inline JSValue
* jsBoolean(bool b
)
238 return b
? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
241 ALWAYS_INLINE JSValue
* jsNumber(double d
)
243 JSValue
* v
= JSImmediate::from(d
);
244 return v
? v
: jsNumberCell(d
);
247 ALWAYS_INLINE JSValue
* jsNumber(int i
)
249 JSValue
* v
= JSImmediate::from(i
);
250 return v
? v
: jsNumberCell(i
);
253 ALWAYS_INLINE JSValue
* jsNumber(unsigned i
)
255 JSValue
* v
= JSImmediate::from(i
);
256 return v
? v
: jsNumberCell(i
);
259 ALWAYS_INLINE JSValue
* jsNumber(long i
)
261 JSValue
* v
= JSImmediate::from(i
);
262 return v
? v
: jsNumberCell(i
);
265 ALWAYS_INLINE JSValue
* jsNumber(unsigned long i
)
267 JSValue
* v
= JSImmediate::from(i
);
268 return v
? v
: jsNumberCell(i
);
271 ALWAYS_INLINE JSValue
* jsNumber(long long i
)
273 JSValue
* v
= JSImmediate::from(i
);
274 return v
? v
: jsNumberCell(static_cast<double>(i
));
277 ALWAYS_INLINE JSValue
* jsNumber(unsigned long long i
)
279 JSValue
* v
= JSImmediate::from(i
);
280 return v
? v
: jsNumberCell(static_cast<double>(i
));
283 ALWAYS_INLINE JSValue
* jsNumberFromAnd(ExecState
*exec
, JSValue
* v1
, JSValue
* v2
)
285 if (JSImmediate::areBothImmediateNumbers(v1
, v2
))
286 return JSImmediate::andImmediateNumbers(v1
, v2
);
287 return jsNumber(v1
->toInt32(exec
) & v2
->toInt32(exec
));
290 inline JSValue::JSValue()
294 inline JSValue::~JSValue()
298 inline JSCell::JSCell()
302 inline JSCell::~JSCell()
306 inline bool JSCell::isNumber() const
308 return type() == NumberType
;
311 inline bool JSCell::isString() const
313 return type() == StringType
;
316 inline bool JSCell::isObject() const
318 return type() == ObjectType
;
321 inline bool JSCell::marked() const
323 return Collector::isCellMarked(this);
326 inline void JSCell::mark()
328 return Collector::markCell(this);
331 ALWAYS_INLINE JSCell
* JSValue::asCell()
333 ASSERT(!JSImmediate::isImmediate(this));
334 return static_cast<JSCell
*>(this);
337 ALWAYS_INLINE
const JSCell
* JSValue::asCell() const
339 ASSERT(!JSImmediate::isImmediate(this));
340 return static_cast<const JSCell
*>(this);
343 inline bool JSValue::isUndefined() const
345 return this == jsUndefined();
348 inline bool JSValue::isNull() const
350 return this == jsNull();
353 inline bool JSValue::isUndefinedOrNull() const
355 return JSImmediate::isUndefinedOrNull(this);
358 inline bool JSValue::isBoolean() const
360 return JSImmediate::isBoolean(this);
363 inline bool JSValue::isNumber() const
365 return JSImmediate::isNumber(this) ||
366 (!JSImmediate::isImmediate(this) && asCell()->isNumber());
369 inline bool JSValue::isString() const
371 return !JSImmediate::isImmediate(this) && asCell()->isString();
374 inline bool JSValue::isObject() const
376 return !JSImmediate::isImmediate(this) && asCell()->isObject();
379 inline bool JSValue::getBoolean(bool& v
) const
381 if (JSImmediate::isBoolean(this)) {
382 v
= JSImmediate::toBoolean(this);
389 inline bool JSValue::getBoolean() const
391 return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false;
394 inline bool JSValue::getNumber(double& v
) const
396 if (JSImmediate::isImmediate(this)) {
397 return JSImmediate::getNumber(this, v
);
399 return asCell()->getNumber(v
);
402 inline double JSValue::getNumber() const
404 return JSImmediate::isImmediate(this) ? JSImmediate::getNumber(this) : asCell()->getNumber();
407 inline bool JSValue::getString(UString
& s
) const
409 return !JSImmediate::isImmediate(this) && asCell()->getString(s
);
412 inline UString
JSValue::getString() const
414 return JSImmediate::isImmediate(this) ? UString() : asCell()->getString();
417 inline JSObject
*JSValue::getObject()
419 return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
422 inline const JSObject
*JSValue::getObject() const
424 return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
427 ALWAYS_INLINE
bool JSValue::getUInt32(uint32_t& v
) const
429 return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v
) : asCell()->getUInt32(v
);
432 ALWAYS_INLINE
bool JSValue::getTruncatedInt32(int32_t& v
) const
434 return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v
) : asCell()->getTruncatedInt32(v
);
437 inline bool JSValue::getTruncatedUInt32(uint32_t& v
) const
439 return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v
) : asCell()->getTruncatedUInt32(v
);
442 inline void JSValue::mark()
444 ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
448 inline bool JSValue::marked() const
450 return JSImmediate::isImmediate(this) || asCell()->marked();
453 inline JSType
JSValue::type() const
455 return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type();
458 inline JSValue
* JSValue::toPrimitive(ExecState
* exec
, JSType preferredType
) const
460 return JSImmediate::isImmediate(this) ? const_cast<JSValue
*>(this) : asCell()->toPrimitive(exec
, preferredType
);
463 inline bool JSValue::getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
*& value
)
465 if (JSImmediate::isImmediate(this)) {
466 number
= JSImmediate::toDouble(this);
470 return asCell()->getPrimitiveNumber(exec
, number
, value
);
473 inline bool JSValue::toBoolean(ExecState
*exec
) const
475 return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec
);
478 ALWAYS_INLINE
double JSValue::toNumber(ExecState
*exec
) const
480 return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec
);
483 ALWAYS_INLINE JSValue
* JSValue::toJSNumber(ExecState
* exec
) const
485 return JSImmediate::isNumber(this) ? const_cast<JSValue
*>(this) : jsNumber(this->toNumber(exec
));
488 inline UString
JSValue::toString(ExecState
*exec
) const
490 return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec
);
493 inline JSObject
* JSValue::toObject(ExecState
* exec
) const
495 return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec
) : asCell()->toObject(exec
);
498 ALWAYS_INLINE
int32_t JSValue::toInt32(ExecState
* exec
) const
501 if (getTruncatedInt32(i
))
504 return toInt32SlowCase(exec
, ok
);
507 inline uint32_t JSValue::toUInt32(ExecState
* exec
) const
510 if (getTruncatedUInt32(i
))
513 return toUInt32SlowCase(exec
, ok
);
516 inline int32_t JSValue::toInt32(double val
)
518 if (!(val
>= -2147483648.0 && val
< 2147483648.0)) {
520 return toInt32SlowCase(val
, ignored
);
522 return static_cast<int32_t>(val
);
525 inline int32_t JSValue::toUInt32(double val
)
527 if (!(val
>= 0.0 && val
< 4294967296.0)) {
529 return toUInt32SlowCase(val
, ignored
);
531 return static_cast<uint32_t>(val
);
534 inline int32_t JSValue::toInt32(ExecState
* exec
, bool& ok
) const
537 if (getTruncatedInt32(i
)) {
541 return toInt32SlowCase(exec
, ok
);
544 inline uint32_t JSValue::toUInt32(ExecState
* exec
, bool& ok
) const
547 if (getTruncatedUInt32(i
)) {
551 return toUInt32SlowCase(exec
, ok
);
554 inline bool JSValue::implementsCall() const
556 if (JSImmediate::isImmediate(this))
557 return false; // immediate values are never calleable.
559 return asCell()->implementsCall();
564 #endif // KJS_VALUE_H