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 | |
42 | namespace KJS { |
43 | |
44 | struct ClassInfo; |
45 | class ExecState; |
46 | class JSObject; |
47 | class 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 | */ |
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() |
60 | |
61 | private: |
62 | JSValue(); |
63 | virtual ~JSValue(); |
64 | |
65 | public: |
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 | |
139 | private: |
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 | |
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; |
161 | private: |
162 | explicit JSCell(); |
163 | virtual ~JSCell(); |
164 | public: |
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 | |
202 | KJS_EXPORT JSValue *jsNumberCell(double); |
203 | |
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); |
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 |
212 | JSCell *jsOwnedString(const UString&); |
213 | |
214 | inline JSValue* jsUndefined() |
215 | { |
216 | return JSImmediate::undefinedImmediate(); |
217 | } |
218 | |
219 | inline JSValue* jsNull() |
220 | { |
221 | return JSImmediate::nullImmediate(); |
222 | } |
223 | |
224 | inline 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 | |
233 | inline JSValue* jsBoolean(bool b) |
234 | { |
235 | return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate(); |
236 | } |
237 | |
238 | ALWAYS_INLINE JSValue* jsNumber(double d) |
239 | { |
240 | JSValue* v = JSImmediate::from(d); |
241 | return v ? v : jsNumberCell(d); |
242 | } |
243 | |
244 | ALWAYS_INLINE JSValue* jsNumber(int i) |
245 | { |
246 | JSValue* v = JSImmediate::from(i); |
247 | return v ? v : jsNumberCell(i); |
248 | } |
249 | |
250 | ALWAYS_INLINE JSValue* jsNumber(unsigned i) |
251 | { |
252 | JSValue* v = JSImmediate::from(i); |
253 | return v ? v : jsNumberCell(i); |
254 | } |
255 | |
256 | ALWAYS_INLINE JSValue* jsNumber(long i) |
257 | { |
258 | JSValue* v = JSImmediate::from(i); |
259 | return v ? v : jsNumberCell(i); |
260 | } |
261 | |
262 | ALWAYS_INLINE JSValue* jsNumber(unsigned long i) |
263 | { |
264 | JSValue* v = JSImmediate::from(i); |
265 | return v ? v : jsNumberCell(i); |
266 | } |
267 | |
268 | ALWAYS_INLINE JSValue* jsNumber(long long i) |
269 | { |
270 | JSValue* v = JSImmediate::from(i); |
271 | return v ? v : jsNumberCell(static_cast<double>(i)); |
272 | } |
273 | |
274 | ALWAYS_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 | |
280 | ALWAYS_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 | |
287 | inline JSValue::JSValue() |
288 | { |
289 | } |
290 | |
291 | inline JSValue::~JSValue() |
292 | { |
293 | } |
294 | |
295 | inline JSCell::JSCell() |
296 | { |
297 | } |
298 | |
299 | inline JSCell::~JSCell() |
300 | { |
301 | } |
302 | |
303 | inline bool JSCell::isNumber() const |
304 | { |
305 | return type() == NumberType; |
306 | } |
307 | |
308 | inline bool JSCell::isString() const |
309 | { |
310 | return type() == StringType; |
311 | } |
312 | |
313 | inline bool JSCell::isObject() const |
314 | { |
315 | return type() == ObjectType; |
316 | } |
317 | |
318 | inline bool JSCell::marked() const |
319 | { |
320 | return Collector::isCellMarked(this); |
321 | } |
322 | |
323 | inline void JSCell::mark() |
324 | { |
325 | return Collector::markCell(this); |
326 | } |
327 | |
328 | ALWAYS_INLINE JSCell* JSValue::asCell() |
329 | { |
330 | ASSERT(!JSImmediate::isImmediate(this)); |
331 | return static_cast<JSCell*>(this); |
332 | } |
333 | |
334 | ALWAYS_INLINE const JSCell* JSValue::asCell() const |
335 | { |
336 | ASSERT(!JSImmediate::isImmediate(this)); |
337 | return static_cast<const JSCell*>(this); |
338 | } |
339 | |
340 | inline bool JSValue::isUndefined() const |
341 | { |
342 | return this == jsUndefined(); |
343 | } |
344 | |
345 | inline bool JSValue::isNull() const |
346 | { |
347 | return this == jsNull(); |
348 | } |
349 | |
350 | inline bool JSValue::isUndefinedOrNull() const |
351 | { |
352 | return JSImmediate::isUndefinedOrNull(this); |
353 | } |
354 | |
355 | inline bool JSValue::isBoolean() const |
356 | { |
357 | return JSImmediate::isBoolean(this); |
358 | } |
359 | |
360 | inline bool JSValue::isNumber() const |
361 | { |
362 | return JSImmediate::isNumber(this) || |
363 | (!JSImmediate::isImmediate(this) && asCell()->isNumber()); |
364 | } |
365 | |
366 | inline bool JSValue::isString() const |
367 | { |
368 | return !JSImmediate::isImmediate(this) && asCell()->isString(); |
369 | } |
370 | |
371 | inline bool JSValue::isObject() const |
372 | { |
373 | return !JSImmediate::isImmediate(this) && asCell()->isObject(); |
374 | } |
375 | |
376 | inline 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 | |
386 | inline bool JSValue::getBoolean() const |
387 | { |
388 | return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false; |
389 | } |
390 | |
391 | inline 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 | |
399 | inline double JSValue::getNumber() const |
400 | { |
401 | return JSImmediate::isImmediate(this) ? JSImmediate::getNumber(this) : asCell()->getNumber(); |
402 | } |
403 | |
404 | inline bool JSValue::getString(UString& s) const |
405 | { |
406 | return !JSImmediate::isImmediate(this) && asCell()->getString(s); |
407 | } |
408 | |
409 | inline UString JSValue::getString() const |
410 | { |
411 | return JSImmediate::isImmediate(this) ? UString() : asCell()->getString(); |
412 | } |
413 | |
414 | inline JSObject *JSValue::getObject() |
415 | { |
416 | return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject(); |
417 | } |
418 | |
419 | inline const JSObject *JSValue::getObject() const |
420 | { |
421 | return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject(); |
422 | } |
423 | |
424 | ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const |
425 | { |
426 | return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v) : asCell()->getUInt32(v); |
427 | } |
428 | |
429 | ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const |
430 | { |
431 | return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v) : asCell()->getTruncatedInt32(v); |
432 | } |
433 | |
434 | inline bool JSValue::getTruncatedUInt32(uint32_t& v) const |
435 | { |
436 | return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v); |
437 | } |
438 | |
439 | inline void JSValue::mark() |
440 | { |
441 | ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark() |
442 | asCell()->mark(); |
443 | } |
444 | |
445 | inline bool JSValue::marked() const |
446 | { |
447 | return JSImmediate::isImmediate(this) || asCell()->marked(); |
448 | } |
449 | |
450 | inline JSType JSValue::type() const |
451 | { |
452 | return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type(); |
453 | } |
454 | |
455 | inline JSValue* JSValue::toPrimitive(ExecState* exec, JSType preferredType) const |
456 | { |
457 | return JSImmediate::isImmediate(this) ? const_cast<JSValue*>(this) : asCell()->toPrimitive(exec, preferredType); |
458 | } |
459 | |
460 | inline 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 | |
470 | inline bool JSValue::toBoolean(ExecState *exec) const |
471 | { |
472 | return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec); |
473 | } |
474 | |
475 | ALWAYS_INLINE double JSValue::toNumber(ExecState *exec) const |
476 | { |
477 | return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec); |
478 | } |
479 | |
480 | ALWAYS_INLINE JSValue* JSValue::toJSNumber(ExecState* exec) const |
481 | { |
482 | return JSImmediate::isNumber(this) ? const_cast<JSValue*>(this) : jsNumber(this->toNumber(exec)); |
483 | } |
484 | |
485 | inline UString JSValue::toString(ExecState *exec) const |
486 | { |
487 | return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec); |
488 | } |
489 | |
490 | inline JSObject* JSValue::toObject(ExecState* exec) const |
491 | { |
492 | return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : asCell()->toObject(exec); |
493 | } |
494 | |
495 | ALWAYS_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 | |
504 | inline 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 | |
513 | inline 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 | |
522 | inline 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 | |
531 | inline 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 | |
541 | inline 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 | |
551 | inline 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 | |