1/*
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.
6 *
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.
11 *
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.
16 *
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.
21 *
22 */
23
24#ifndef KJS_VALUE_H
25#define KJS_VALUE_H
26
27#include "JSImmediate.h"
28#include "ustring.h"
29#include "collector.h"
30#include <wtf/Noncopyable.h>
31#include <stddef.h> // for size_t
32
33#ifndef NDEBUG // protection against problems if committing with KJS_VERBOSE on
34
35// Uncomment this to enable very verbose output from KJS
36//#define KJS_VERBOSE
37// Uncomment this to debug memory allocation and garbage collection
38//#define KJS_DEBUG_MEM
39
40#endif
41
42namespace KJS {
43
44struct ClassInfo;
45class ExecState;
46class JSObject;
47class JSCell;
48
49/**
50 * JSValue is the base type for all primitives (Undefined, Null, Boolean,
51 * String, Number) and objects in ECMAScript.
52 *
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
55 * JSObject.
56 */
57class KJS_EXPORT JSValue : Noncopyable {
58 friend class JSCell; // so it can derive from this class
59 friend class Collector; // so it can call asCell()
60
61private:
62 JSValue();
63 virtual ~JSValue();
64
65public:
66 // Querying the type.
67 JSType type() const;
68 bool isUndefined() const;
69 bool isNull() 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;
76
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
86
87 // Extracting integer values.
88 bool getUInt32(uint32_t&) const;
89 bool getTruncatedInt32(int32_t&) const;
90 bool getTruncatedUInt32(uint32_t&) const;
91
92 JSValue* getByIndex(ExecState* exec, unsigned propertyName) const;
93
94 // Basic conversions.
95 JSValue* toPrimitive(ExecState* exec, JSType preferredType = UnspecifiedType) const;
96 bool getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value);
97
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;
103
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;
112
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);
116
117 // Floating point conversions.
118 float toFloat(ExecState*) const;
119
120 // Object-level properties...
121
122 /**
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
126 *
127 * @return true if this is an object implementing the call() method, otherwise
128 * false
129 */
130 bool implementsCall() const;
131
132 // Garbage collection.
133 void mark();
134 bool marked() const;
135
136 static int32_t toInt32SlowCase(double, bool& ok);
137 static uint32_t toUInt32SlowCase(double, bool& ok);
138
139private:
140 int32_t toInt32SlowCase(ExecState*, bool& ok) const;
141 uint32_t toUInt32SlowCase(ExecState*, bool& ok) const;
142
143 // Implementation details.
144 JSCell *asCell();
145 const JSCell *asCell() const;
146
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&);
152#endif
153};
154
155class 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;
161private:
162 explicit JSCell();
163 virtual ~JSCell();
164public:
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;
171
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
179
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;
184
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;
192
193 // Higher-level (object-like) properties:
194 virtual bool implementsCall() const;
195
196 // Garbage collection.
197 void *operator new(size_t);
198 virtual void mark();
199 bool marked() const;
200};
201
202KJS_EXPORT JSValue *jsNumberCell(double);
203
204KJS_EXPORT JSCell* jsString(); // returns empty string
205KJS_EXPORT JSCell* jsString(const UString&); // returns empty string if passed null string
206KJS_EXPORT JSCell* jsString(const char* = ""); // returns empty string if passed 0
207KJS_EXPORT JSCell* jsString(const char* s, int len);
208
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
212JSCell *jsOwnedString(const UString&);
213
214inline JSValue* jsUndefined()
215{
216 return JSImmediate::undefinedImmediate();
217}
218
219inline JSValue* jsNull()
220{
221 return JSImmediate::nullImmediate();
222}
223
224inline JSValue* jsNaN()
225{
226 static const union {
227 uint64_t bits;
228 double d;
229 } nan = { 0x7ff80000ULL << 32 };
230 return jsNumberCell(nan.d);
231}
232
233inline JSValue* jsBoolean(bool b)
234{
235 return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
236}
237
238ALWAYS_INLINE JSValue* jsNumber(double d)
239{
240 JSValue* v = JSImmediate::from(d);
241 return v ? v : jsNumberCell(d);
242}
243
244ALWAYS_INLINE JSValue* jsNumber(int i)
245{
246 JSValue* v = JSImmediate::from(i);
247 return v ? v : jsNumberCell(i);
248}
249
250ALWAYS_INLINE JSValue* jsNumber(unsigned i)
251{
252 JSValue* v = JSImmediate::from(i);
253 return v ? v : jsNumberCell(i);
254}
255
256ALWAYS_INLINE JSValue* jsNumber(long i)
257{
258 JSValue* v = JSImmediate::from(i);
259 return v ? v : jsNumberCell(i);
260}
261
262ALWAYS_INLINE JSValue* jsNumber(unsigned long i)
263{
264 JSValue* v = JSImmediate::from(i);
265 return v ? v : jsNumberCell(i);
266}
267
268ALWAYS_INLINE JSValue* jsNumber(long long i)
269{
270 JSValue* v = JSImmediate::from(i);
271 return v ? v : jsNumberCell(static_cast<double>(i));
272}
273
274ALWAYS_INLINE JSValue* jsNumber(unsigned long long i)
275{
276 JSValue* v = JSImmediate::from(i);
277 return v ? v : jsNumberCell(static_cast<double>(i));
278}
279
280ALWAYS_INLINE JSValue* jsNumberFromAnd(ExecState *exec, JSValue* v1, JSValue* v2)
281{
282 if (JSImmediate::areBothImmediateNumbers(v1, v2))
283 return JSImmediate::andImmediateNumbers(v1, v2);
284 return jsNumber(v1->toInt32(exec) & v2->toInt32(exec));
285}
286
287inline JSValue::JSValue()
288{
289}
290
291inline JSValue::~JSValue()
292{
293}
294
295inline JSCell::JSCell()
296{
297}
298
299inline JSCell::~JSCell()
300{
301}
302
303inline bool JSCell::isNumber() const
304{
305 return type() == NumberType;
306}
307
308inline bool JSCell::isString() const
309{
310 return type() == StringType;
311}
312
313inline bool JSCell::isObject() const
314{
315 return type() == ObjectType;
316}
317
318inline bool JSCell::marked() const
319{
320 return Collector::isCellMarked(this);
321}
322
323inline void JSCell::mark()
324{
325 return Collector::markCell(this);
326}
327
328ALWAYS_INLINE JSCell* JSValue::asCell()
329{
330 ASSERT(!JSImmediate::isImmediate(this));
331 return static_cast<JSCell*>(this);
332}
333
334ALWAYS_INLINE const JSCell* JSValue::asCell() const
335{
336 ASSERT(!JSImmediate::isImmediate(this));
337 return static_cast<const JSCell*>(this);
338}
339
340inline bool JSValue::isUndefined() const
341{
342 return this == jsUndefined();
343}
344
345inline bool JSValue::isNull() const
346{
347 return this == jsNull();
348}
349
350inline bool JSValue::isUndefinedOrNull() const
351{
352 return JSImmediate::isUndefinedOrNull(this);
353}
354
355inline bool JSValue::isBoolean() const
356{
357 return JSImmediate::isBoolean(this);
358}
359
360inline bool JSValue::isNumber() const
361{
362 return JSImmediate::isNumber(this) ||
363 (!JSImmediate::isImmediate(this) && asCell()->isNumber());
364}
365
366inline bool JSValue::isString() const
367{
368 return !JSImmediate::isImmediate(this) && asCell()->isString();
369}
370
371inline bool JSValue::isObject() const
372{
373 return !JSImmediate::isImmediate(this) && asCell()->isObject();
374}
375
376inline bool JSValue::getBoolean(bool& v) const
377{
378 if (JSImmediate::isBoolean(this)) {
379 v = JSImmediate::toBoolean(this);
380 return true;
381 }
382
383 return false;
384}
385
386inline bool JSValue::getBoolean() const
387{
388 return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false;
389}
390
391inline bool JSValue::getNumber(double& v) const
392{
393 if (JSImmediate::isImmediate(this)) {
394 return JSImmediate::getNumber(this, v);
395 }
396 return asCell()->getNumber(v);
397}
398
399inline double JSValue::getNumber() const
400{
401 return JSImmediate::isImmediate(this) ? JSImmediate::getNumber(this) : asCell()->getNumber();
402}
403
404inline bool JSValue::getString(UString& s) const
405{
406 return !JSImmediate::isImmediate(this) && asCell()->getString(s);
407}
408
409inline UString JSValue::getString() const
410{
411 return JSImmediate::isImmediate(this) ? UString() : asCell()->getString();
412}
413
414inline JSObject *JSValue::getObject()
415{
416 return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
417}
418
419inline const JSObject *JSValue::getObject() const
420{
421 return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
422}
423
424ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
425{
426 return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v) : asCell()->getUInt32(v);
427}
428
429ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const
430{
431 return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v) : asCell()->getTruncatedInt32(v);
432}
433
434inline bool JSValue::getTruncatedUInt32(uint32_t& v) const
435{
436 return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v);
437}
438
439inline void JSValue::mark()
440{
441 ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
442 asCell()->mark();
443}
444
445inline bool JSValue::marked() const
446{
447 return JSImmediate::isImmediate(this) || asCell()->marked();
448}
449
450inline JSType JSValue::type() const
451{
452 return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type();
453}
454
455inline JSValue* JSValue::toPrimitive(ExecState* exec, JSType preferredType) const
456{
457 return JSImmediate::isImmediate(this) ? const_cast<JSValue*>(this) : asCell()->toPrimitive(exec, preferredType);
458}
459
460inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value)
461{
462 if (JSImmediate::isImmediate(this)) {
463 number = JSImmediate::toDouble(this);
464 value = this;
465 return true;
466 }
467 return asCell()->getPrimitiveNumber(exec, number, value);
468}
469
470inline bool JSValue::toBoolean(ExecState *exec) const
471{
472 return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec);
473}
474
475ALWAYS_INLINE double JSValue::toNumber(ExecState *exec) const
476{
477 return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec);
478}
479
480ALWAYS_INLINE JSValue* JSValue::toJSNumber(ExecState* exec) const
481{
482 return JSImmediate::isNumber(this) ? const_cast<JSValue*>(this) : jsNumber(this->toNumber(exec));
483}
484
485inline UString JSValue::toString(ExecState *exec) const
486{
487 return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec);
488}
489
490inline JSObject* JSValue::toObject(ExecState* exec) const
491{
492 return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : asCell()->toObject(exec);
493}
494
495ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
496{
497 int32_t i;
498 if (getTruncatedInt32(i))
499 return i;
500 bool ok;
501 return toInt32SlowCase(exec, ok);
502}
503
504inline uint32_t JSValue::toUInt32(ExecState* exec) const
505{
506 uint32_t i;
507 if (getTruncatedUInt32(i))
508 return i;
509 bool ok;
510 return toUInt32SlowCase(exec, ok);
511}
512
513inline int32_t JSValue::toInt32(double val)
514{
515 if (!(val >= -2147483648.0 && val < 2147483648.0)) {
516 bool ignored;
517 return toInt32SlowCase(val, ignored);
518 }
519 return static_cast<int32_t>(val);
520}
521
522inline int32_t JSValue::toUInt32(double val)
523{
524 if (!(val >= 0.0 && val < 4294967296.0)) {
525 bool ignored;
526 return toUInt32SlowCase(val, ignored);
527 }
528 return static_cast<uint32_t>(val);
529}
530
531inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const
532{
533 int32_t i;
534 if (getTruncatedInt32(i)) {
535 ok = true;
536 return i;
537 }
538 return toInt32SlowCase(exec, ok);
539}
540
541inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const
542{
543 uint32_t i;
544 if (getTruncatedUInt32(i)) {
545 ok = true;
546 return i;
547 }
548 return toUInt32SlowCase(exec, ok);
549}
550
551inline bool JSValue::implementsCall() const
552{
553 if (JSImmediate::isImmediate(this))
554 return false; // immediate values are never calleable.
555 else
556 return asCell()->implementsCall();
557}
558
559} // namespace
560
561#endif // KJS_VALUE_H
562