2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2007 Apple Inc. All rights reserved.
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.
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.
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.
26 #include "JSImmediate.h"
27 #include "collector.h"
29 #include <stddef.h> // for size_t
40 * JSValue is the base type for all primitives (Undefined, Null, Boolean,
41 * String, Number) and objects in ECMAScript.
43 * Note: you should never inherit from JSValue as it is for primitive types
44 * only (all of which are provided internally by KJS). Instead, inherit from
47 class JSValue : Noncopyable {
48 friend class JSCell; // so it can derive from this class
49 friend class Collector; // so it can call asCell()
58 bool isUndefined() const;
60 bool isUndefinedOrNull() const;
61 bool isBoolean() const;
62 bool isNumber() const;
63 bool isString() const;
64 bool isObject() const;
65 bool isObject(const ClassInfo *) const;
67 // Extracting the value.
68 bool getBoolean(bool&) const;
69 bool getBoolean() const; // false if not a boolean
70 bool getNumber(double&) const;
71 double getNumber() const; // NaN if not a number
72 bool getString(UString&) const;
73 UString getString() const; // null string if not a string
74 JSObject *getObject(); // NULL if not an object
75 const JSObject *getObject() const; // NULL if not an object
77 // Extracting integer values.
78 bool getUInt32(uint32_t&) const;
79 bool getTruncatedInt32(int32_t&) const;
80 bool getTruncatedUInt32(uint32_t&) const;
83 JSValue* toPrimitive(ExecState* exec, JSType preferredType = UnspecifiedType) const;
84 bool getPrimitiveNumber(ExecState* exec, double& number) const;
86 bool toBoolean(ExecState *exec) const;
87 double toNumber(ExecState *exec) const;
88 JSValue* toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number.
89 UString toString(ExecState *exec) const;
90 JSObject *toObject(ExecState *exec) const;
92 // Integer conversions.
93 double toInteger(ExecState*) const;
94 double toIntegerPreserveNaN(ExecState*) const;
95 int32_t toInt32(ExecState*) const;
96 int32_t toInt32(ExecState*, bool& ok) const;
97 uint32_t toUInt32(ExecState*) const;
98 uint32_t toUInt32(ExecState*, bool& ok) const;
100 // Floating point conversions.
101 float toFloat(ExecState*) const;
103 // Garbage collection.
108 int32_t toInt32SlowCase(ExecState*, bool& ok) const;
109 uint32_t toUInt32SlowCase(ExecState*, bool& ok) const;
111 // Implementation details.
113 const JSCell *asCell() const;
115 // Give a compile time error if we try to copy one of these.
116 JSValue(const JSValue&);
117 JSValue& operator=(const JSValue&);
120 class JSCell : public JSValue {
121 friend class Collector;
122 friend class NumberImp;
123 friend class StringImp;
124 friend class JSObject;
125 friend class GetterSetterImp;
130 // Querying the type.
131 virtual JSType type() const = 0;
132 bool isNumber() const;
133 bool isString() const;
134 bool isObject() const;
135 bool isObject(const ClassInfo *) const;
137 // Extracting the value.
138 bool getNumber(double&) const;
139 double getNumber() const; // NaN if not a number
140 bool getString(UString&) const;
141 UString getString() const; // null string if not a string
142 JSObject *getObject(); // NULL if not an object
143 const JSObject *getObject() const; // NULL if not an object
145 // Extracting integer values.
146 virtual bool getUInt32(uint32_t&) const;
147 virtual bool getTruncatedInt32(int32_t&) const;
148 virtual bool getTruncatedUInt32(uint32_t&) const;
150 // Basic conversions.
151 virtual JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const = 0;
152 virtual bool getPrimitiveNumber(ExecState* exec, double& number) const = 0;
153 virtual bool toBoolean(ExecState *exec) const = 0;
154 virtual double toNumber(ExecState *exec) const = 0;
155 virtual UString toString(ExecState *exec) const = 0;
156 virtual JSObject *toObject(ExecState *exec) const = 0;
158 // Garbage collection.
159 void *operator new(size_t);
164 JSValue *jsNumberCell(double);
166 JSCell *jsString(const UString&); // returns empty string if passed null string
167 JSCell *jsString(const char* = ""); // returns empty string if passed 0
169 // should be used for strings that are owned by an object that will
170 // likely outlive the JSValue this makes, such as the parse tree or a
171 // DOM object that contains a UString
172 JSCell *jsOwnedString(const UString&);
174 extern const double NaN;
175 extern const double Inf;
177 inline JSValue *jsUndefined()
179 return JSImmediate::undefinedImmediate();
182 inline JSValue *jsNull()
184 return JSImmediate::nullImmediate();
187 inline JSValue *jsNaN()
192 } nan = { 0x7ff80000ULL << 32 };
193 return jsNumberCell(nan.d);
196 inline JSValue *jsBoolean(bool b)
198 return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
201 ALWAYS_INLINE JSValue* jsNumber(double d)
203 JSValue* v = JSImmediate::from(d);
204 return v ? v : jsNumberCell(d);
207 ALWAYS_INLINE JSValue* jsNumber(int i)
209 JSValue* v = JSImmediate::from(i);
210 return v ? v : jsNumberCell(i);
213 ALWAYS_INLINE JSValue* jsNumber(unsigned i)
215 JSValue* v = JSImmediate::from(i);
216 return v ? v : jsNumberCell(i);
219 ALWAYS_INLINE JSValue* jsNumber(long i)
221 JSValue* v = JSImmediate::from(i);
222 return v ? v : jsNumberCell(i);
225 ALWAYS_INLINE JSValue* jsNumber(unsigned long i)
227 JSValue* v = JSImmediate::from(i);
228 return v ? v : jsNumberCell(i);
231 ALWAYS_INLINE JSValue* jsNumber(long long i)
233 JSValue* v = JSImmediate::from(i);
234 return v ? v : jsNumberCell(i);
237 ALWAYS_INLINE JSValue* jsNumber(unsigned long long i)
239 JSValue* v = JSImmediate::from(i);
240 return v ? v : jsNumberCell(i);
243 ALWAYS_INLINE JSValue* jsNumberFromAnd(ExecState *exec, JSValue* v1, JSValue* v2)
245 if (JSImmediate::areBothImmediateNumbers(v1, v2))
246 return JSImmediate::andImmediateNumbers(v1, v2);
247 return jsNumber(v1->toInt32(exec) & v2->toInt32(exec));
250 inline JSValue::JSValue()
254 inline JSValue::~JSValue()
258 inline JSCell::JSCell()
262 inline JSCell::~JSCell()
266 inline bool JSCell::isNumber() const
268 return type() == NumberType;
271 inline bool JSCell::isString() const
273 return type() == StringType;
276 inline bool JSCell::isObject() const
278 return type() == ObjectType;
281 inline bool JSCell::marked() const
283 return Collector::isCellMarked(this);
286 inline void JSCell::mark()
288 return Collector::markCell(this);
291 inline JSCell *JSValue::asCell()
293 ASSERT(!JSImmediate::isImmediate(this));
294 return static_cast<JSCell *>(this);
297 inline const JSCell *JSValue::asCell() const
299 ASSERT(!JSImmediate::isImmediate(this));
300 return static_cast<const JSCell *>(this);
303 inline bool JSValue::isUndefined() const
305 return this == jsUndefined();
308 inline bool JSValue::isNull() const
310 return this == jsNull();
313 inline bool JSValue::isUndefinedOrNull() const
315 return JSImmediate::isUndefinedOrNull(this);
318 inline bool JSValue::isBoolean() const
320 return JSImmediate::isBoolean(this);
323 inline bool JSValue::isNumber() const
325 return JSImmediate::isNumber(this) || (!JSImmediate::isImmediate(this) && asCell()->isNumber());
328 inline bool JSValue::isString() const
330 return !JSImmediate::isImmediate(this) && asCell()->isString();
333 inline bool JSValue::isObject() const
335 return !JSImmediate::isImmediate(this) && asCell()->isObject();
338 inline bool JSValue::getBoolean(bool& v) const
340 if (JSImmediate::isBoolean(this)) {
341 v = JSImmediate::toBoolean(this);
348 inline bool JSValue::getBoolean() const
350 return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false;
353 inline bool JSValue::getNumber(double& v) const
355 if (JSImmediate::isImmediate(this)) {
356 v = JSImmediate::toDouble(this);
359 return asCell()->getNumber(v);
362 inline double JSValue::getNumber() const
364 return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->getNumber();
367 inline bool JSValue::getString(UString& s) const
369 return !JSImmediate::isImmediate(this) && asCell()->getString(s);
372 inline UString JSValue::getString() const
374 return JSImmediate::isImmediate(this) ? UString() : asCell()->getString();
377 inline JSObject *JSValue::getObject()
379 return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
382 inline const JSObject *JSValue::getObject() const
384 return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
387 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
389 return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v) : asCell()->getUInt32(v);
392 ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const
394 return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v) : asCell()->getTruncatedInt32(v);
397 inline bool JSValue::getTruncatedUInt32(uint32_t& v) const
399 return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v);
402 inline void JSValue::mark()
404 ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
408 inline bool JSValue::marked() const
410 return JSImmediate::isImmediate(this) || asCell()->marked();
413 inline JSType JSValue::type() const
415 return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type();
418 inline JSValue* JSValue::toPrimitive(ExecState* exec, JSType preferredType) const
420 return JSImmediate::isImmediate(this) ? const_cast<JSValue*>(this) : asCell()->toPrimitive(exec, preferredType);
423 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number) const
425 if (JSImmediate::isImmediate(this)) {
426 number = JSImmediate::toDouble(this);
429 return asCell()->getPrimitiveNumber(exec, number);
432 inline bool JSValue::toBoolean(ExecState *exec) const
434 return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec);
437 ALWAYS_INLINE double JSValue::toNumber(ExecState *exec) const
439 return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec);
442 ALWAYS_INLINE JSValue* JSValue::toJSNumber(ExecState* exec) const
444 return JSImmediate::isNumber(this) ? const_cast<JSValue*>(this) : jsNumber(this->toNumber(exec));
447 inline UString JSValue::toString(ExecState *exec) const
449 return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec);
452 inline JSObject* JSValue::toObject(ExecState* exec) const
454 return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : asCell()->toObject(exec);
457 ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
460 if (getTruncatedInt32(i))
463 return toInt32SlowCase(exec, ok);
466 inline uint32_t JSValue::toUInt32(ExecState* exec) const
469 if (getTruncatedUInt32(i))
472 return toUInt32SlowCase(exec, ok);
475 inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const
478 if (getTruncatedInt32(i)) {
482 return toInt32SlowCase(exec, ok);
485 inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const
488 if (getTruncatedUInt32(i)) {
492 return toUInt32SlowCase(exec, ok);
497 #endif // KJS_VALUE_H