1 | /* |
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, 2008, 2009 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 JSValue_h |
24 | #define JSValue_h |
25 | |
26 | #include "CallData.h" |
27 | #include "ConstructData.h" |
28 | #include <stddef.h> // for size_t |
29 | #include <stdint.h> |
30 | #include <wtf/AlwaysInline.h> |
31 | #include <wtf/Assertions.h> |
32 | #include <wtf/HashTraits.h> |
33 | #include <wtf/MathExtras.h> |
34 | |
35 | namespace JSC { |
36 | |
37 | class Identifier; |
38 | class JSCell; |
39 | class JSGlobalData; |
40 | class JSImmediate; |
41 | class JSObject; |
42 | class JSString; |
43 | class PropertySlot; |
44 | class PutPropertySlot; |
45 | class UString; |
46 | |
47 | struct ClassInfo; |
48 | struct Instruction; |
49 | |
50 | enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; |
51 | |
52 | #if USE(JSVALUE32_64) |
53 | typedef int64_t EncodedJSValue; |
54 | #else |
55 | typedef void* EncodedJSValue; |
56 | #endif |
57 | |
58 | double nonInlineNaN(); |
59 | int32_t toInt32SlowCase(double, bool& ok); |
60 | uint32_t toUInt32SlowCase(double, bool& ok); |
61 | |
62 | class JSValue { |
63 | friend class JSImmediate; |
64 | friend struct EncodedJSValueHashTraits; |
65 | friend class JIT; |
66 | friend class JITStubs; |
67 | friend class JITStubCall; |
68 | |
69 | public: |
70 | static EncodedJSValue encode(JSValue value); |
71 | static JSValue decode(EncodedJSValue ptr); |
72 | #if !USE(JSVALUE32_64) |
73 | private: |
74 | static JSValue makeImmediate(intptr_t value); |
75 | intptr_t immediateValue(); |
76 | public: |
77 | #endif |
78 | enum JSNullTag { JSNull }; |
79 | enum JSUndefinedTag { JSUndefined }; |
80 | enum JSTrueTag { JSTrue }; |
81 | enum JSFalseTag { JSFalse }; |
82 | enum EncodeAsDoubleTag { EncodeAsDouble }; |
83 | |
84 | JSValue(); |
85 | JSValue(JSNullTag); |
86 | JSValue(JSUndefinedTag); |
87 | JSValue(JSTrueTag); |
88 | JSValue(JSFalseTag); |
89 | JSValue(JSCell* ptr); |
90 | JSValue(const JSCell* ptr); |
91 | |
92 | // Numbers |
93 | JSValue(EncodeAsDoubleTag, ExecState*, double); |
94 | JSValue(ExecState*, double); |
95 | JSValue(ExecState*, char); |
96 | JSValue(ExecState*, unsigned char); |
97 | JSValue(ExecState*, short); |
98 | JSValue(ExecState*, unsigned short); |
99 | JSValue(ExecState*, int); |
100 | JSValue(ExecState*, unsigned); |
101 | JSValue(ExecState*, long); |
102 | JSValue(ExecState*, unsigned long); |
103 | JSValue(ExecState*, long long); |
104 | JSValue(ExecState*, unsigned long long); |
105 | JSValue(JSGlobalData*, double); |
106 | JSValue(JSGlobalData*, int); |
107 | JSValue(JSGlobalData*, unsigned); |
108 | |
109 | operator bool() const; |
110 | bool operator==(const JSValue& other) const; |
111 | bool operator!=(const JSValue& other) const; |
112 | |
113 | bool isInt32() const; |
114 | bool isUInt32() const; |
115 | bool isDouble() const; |
116 | bool isTrue() const; |
117 | bool isFalse() const; |
118 | |
119 | int32_t asInt32() const; |
120 | uint32_t asUInt32() const; |
121 | double asDouble() const; |
122 | |
123 | // Querying the type. |
124 | bool isUndefined() const; |
125 | bool isNull() const; |
126 | bool isUndefinedOrNull() const; |
127 | bool isBoolean() const; |
128 | bool isNumber() const; |
129 | bool isString() const; |
130 | bool isGetterSetter() const; |
131 | bool isObject() const; |
132 | bool inherits(const ClassInfo*) const; |
133 | |
134 | // Extracting the value. |
135 | bool getBoolean(bool&) const; |
136 | bool getBoolean() const; // false if not a boolean |
137 | bool getNumber(double&) const; |
138 | double uncheckedGetNumber() const; |
139 | bool getString(ExecState* exec, UString&) const; |
140 | UString getString(ExecState* exec) const; // null string if not a string |
141 | JSObject* getObject() const; // 0 if not an object |
142 | |
143 | CallType getCallData(CallData&); |
144 | ConstructType getConstructData(ConstructData&); |
145 | |
146 | // Extracting integer values. |
147 | bool getUInt32(uint32_t&) const; |
148 | |
149 | // Basic conversions. |
150 | JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; |
151 | bool getPrimitiveNumber(ExecState*, double& number, JSValue&); |
152 | |
153 | bool toBoolean(ExecState*) const; |
154 | |
155 | // toNumber conversion is expected to be side effect free if an exception has |
156 | // been set in the ExecState already. |
157 | double toNumber(ExecState*) const; |
158 | JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number. |
159 | UString toString(ExecState*) const; |
160 | UString toPrimitiveString(ExecState*) const; |
161 | JSObject* toObject(ExecState*) const; |
162 | |
163 | // Integer conversions. |
164 | double toInteger(ExecState*) const; |
165 | double toIntegerPreserveNaN(ExecState*) const; |
166 | int32_t toInt32(ExecState*) const; |
167 | int32_t toInt32(ExecState*, bool& ok) const; |
168 | uint32_t toUInt32(ExecState*) const; |
169 | uint32_t toUInt32(ExecState*, bool& ok) const; |
170 | |
171 | #if ENABLE(JSC_ZOMBIES) |
172 | bool isZombie() const; |
173 | #endif |
174 | |
175 | // Floating point conversions (this is a convenience method for webcore; |
176 | // signle precision float is not a representation used in JS or JSC). |
177 | float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } |
178 | |
179 | // Object operations, with the toObject operation included. |
180 | JSValue get(ExecState*, const Identifier& propertyName) const; |
181 | JSValue get(ExecState*, const Identifier& propertyName, PropertySlot&) const; |
182 | JSValue get(ExecState*, unsigned propertyName) const; |
183 | JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; |
184 | void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); |
185 | void put(ExecState*, unsigned propertyName, JSValue); |
186 | |
187 | bool needsThisConversion() const; |
188 | JSObject* toThisObject(ExecState*) const; |
189 | UString toThisString(ExecState*) const; |
190 | JSString* toThisJSString(ExecState*); |
191 | |
192 | static bool equal(ExecState* exec, JSValue v1, JSValue v2); |
193 | static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); |
194 | static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); |
195 | static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); |
196 | static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); |
197 | static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); |
198 | |
199 | JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object |
200 | |
201 | bool isCell() const; |
202 | JSCell* asCell() const; |
203 | |
204 | #ifndef NDEBUG |
205 | char* description(); |
206 | #endif |
207 | |
208 | private: |
209 | enum HashTableDeletedValueTag { HashTableDeletedValue }; |
210 | JSValue(HashTableDeletedValueTag); |
211 | |
212 | inline const JSValue asValue() const { return *this; } |
213 | JSObject* toObjectSlowCase(ExecState*) const; |
214 | JSObject* toThisObjectSlowCase(ExecState*) const; |
215 | |
216 | enum { Int32Tag = 0xffffffff }; |
217 | enum { CellTag = 0xfffffffe }; |
218 | enum { TrueTag = 0xfffffffd }; |
219 | enum { FalseTag = 0xfffffffc }; |
220 | enum { NullTag = 0xfffffffb }; |
221 | enum { UndefinedTag = 0xfffffffa }; |
222 | enum { EmptyValueTag = 0xfffffff9 }; |
223 | enum { DeletedValueTag = 0xfffffff8 }; |
224 | |
225 | enum { LowestTag = DeletedValueTag }; |
226 | |
227 | uint32_t tag() const; |
228 | int32_t payload() const; |
229 | |
230 | JSObject* synthesizePrototype(ExecState*) const; |
231 | JSObject* synthesizeObject(ExecState*) const; |
232 | |
233 | #if USE(JSVALUE32_64) |
234 | union { |
235 | EncodedJSValue asEncodedJSValue; |
236 | double asDouble; |
237 | #if CPU(BIG_ENDIAN) |
238 | struct { |
239 | int32_t tag; |
240 | int32_t payload; |
241 | } asBits; |
242 | #else |
243 | struct { |
244 | int32_t payload; |
245 | int32_t tag; |
246 | } asBits; |
247 | #endif |
248 | } u; |
249 | #else // USE(JSVALUE32_64) |
250 | JSCell* m_ptr; |
251 | #endif // USE(JSVALUE32_64) |
252 | }; |
253 | |
254 | #if USE(JSVALUE32_64) |
255 | typedef IntHash<EncodedJSValue> EncodedJSValueHash; |
256 | |
257 | struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { |
258 | static const bool emptyValueIsZero = false; |
259 | static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); } |
260 | static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } |
261 | static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } |
262 | }; |
263 | #else |
264 | typedef PtrHash<EncodedJSValue> EncodedJSValueHash; |
265 | |
266 | struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { |
267 | static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(value: JSValue(JSValue::HashTableDeletedValue)); } |
268 | static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(value: JSValue(JSValue::HashTableDeletedValue)); } |
269 | }; |
270 | #endif |
271 | |
272 | // Stand-alone helper functions. |
273 | inline JSValue jsNull() |
274 | { |
275 | return JSValue(JSValue::JSNull); |
276 | } |
277 | |
278 | inline JSValue jsUndefined() |
279 | { |
280 | return JSValue(JSValue::JSUndefined); |
281 | } |
282 | |
283 | inline JSValue jsBoolean(bool b) |
284 | { |
285 | return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); |
286 | } |
287 | |
288 | ALWAYS_INLINE JSValue jsDoubleNumber(ExecState* exec, double d) |
289 | { |
290 | return JSValue(JSValue::EncodeAsDouble, exec, d); |
291 | } |
292 | |
293 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, double d) |
294 | { |
295 | return JSValue(exec, d); |
296 | } |
297 | |
298 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, char i) |
299 | { |
300 | return JSValue(exec, i); |
301 | } |
302 | |
303 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned char i) |
304 | { |
305 | return JSValue(exec, i); |
306 | } |
307 | |
308 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, short i) |
309 | { |
310 | return JSValue(exec, i); |
311 | } |
312 | |
313 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned short i) |
314 | { |
315 | return JSValue(exec, i); |
316 | } |
317 | |
318 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, int i) |
319 | { |
320 | return JSValue(exec, i); |
321 | } |
322 | |
323 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned i) |
324 | { |
325 | return JSValue(exec, i); |
326 | } |
327 | |
328 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, long i) |
329 | { |
330 | return JSValue(exec, i); |
331 | } |
332 | |
333 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned long i) |
334 | { |
335 | return JSValue(exec, i); |
336 | } |
337 | |
338 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, long long i) |
339 | { |
340 | return JSValue(exec, i); |
341 | } |
342 | |
343 | ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned long long i) |
344 | { |
345 | return JSValue(exec, i); |
346 | } |
347 | |
348 | ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, double d) |
349 | { |
350 | return JSValue(globalData, d); |
351 | } |
352 | |
353 | ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, int i) |
354 | { |
355 | return JSValue(globalData, i); |
356 | } |
357 | |
358 | ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned i) |
359 | { |
360 | return JSValue(globalData, i); |
361 | } |
362 | |
363 | inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); } |
364 | inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; } |
365 | |
366 | inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); } |
367 | inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; } |
368 | |
369 | inline int32_t toInt32(double val) |
370 | { |
371 | if (!(val >= -2147483648.0 && val < 2147483648.0)) { |
372 | bool ignored; |
373 | return toInt32SlowCase(val, ok&: ignored); |
374 | } |
375 | return static_cast<int32_t>(val); |
376 | } |
377 | |
378 | inline uint32_t toUInt32(double val) |
379 | { |
380 | if (!(val >= 0.0 && val < 4294967296.0)) { |
381 | bool ignored; |
382 | return toUInt32SlowCase(val, ok&: ignored); |
383 | } |
384 | return static_cast<uint32_t>(val); |
385 | } |
386 | |
387 | // FIXME: We should deprecate this and just use JSValue::asCell() instead. |
388 | JSCell* asCell(JSValue); |
389 | |
390 | inline JSCell* asCell(JSValue value) |
391 | { |
392 | return value.asCell(); |
393 | } |
394 | |
395 | ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const |
396 | { |
397 | if (isInt32()) |
398 | return asInt32(); |
399 | bool ignored; |
400 | return toInt32SlowCase(toNumber(exec), ok&: ignored); |
401 | } |
402 | |
403 | inline uint32_t JSValue::toUInt32(ExecState* exec) const |
404 | { |
405 | if (isUInt32()) |
406 | return asInt32(); |
407 | bool ignored; |
408 | return toUInt32SlowCase(toNumber(exec), ok&: ignored); |
409 | } |
410 | |
411 | inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const |
412 | { |
413 | if (isInt32()) { |
414 | ok = true; |
415 | return asInt32(); |
416 | } |
417 | return toInt32SlowCase(toNumber(exec), ok); |
418 | } |
419 | |
420 | inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const |
421 | { |
422 | if (isUInt32()) { |
423 | ok = true; |
424 | return asInt32(); |
425 | } |
426 | return toUInt32SlowCase(toNumber(exec), ok); |
427 | } |
428 | |
429 | #if USE(JSVALUE32_64) |
430 | inline JSValue jsNaN(ExecState* exec) |
431 | { |
432 | return JSValue(exec, nonInlineNaN()); |
433 | } |
434 | |
435 | // JSValue member functions. |
436 | inline EncodedJSValue JSValue::encode(JSValue value) |
437 | { |
438 | return value.u.asEncodedJSValue; |
439 | } |
440 | |
441 | inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) |
442 | { |
443 | JSValue v; |
444 | v.u.asEncodedJSValue = encodedJSValue; |
445 | #if ENABLE(JSC_ZOMBIES) |
446 | ASSERT(!v.isZombie()); |
447 | #endif |
448 | return v; |
449 | } |
450 | |
451 | inline JSValue::JSValue() |
452 | { |
453 | u.asBits.tag = EmptyValueTag; |
454 | u.asBits.payload = 0; |
455 | } |
456 | |
457 | inline JSValue::JSValue(JSNullTag) |
458 | { |
459 | u.asBits.tag = NullTag; |
460 | u.asBits.payload = 0; |
461 | } |
462 | |
463 | inline JSValue::JSValue(JSUndefinedTag) |
464 | { |
465 | u.asBits.tag = UndefinedTag; |
466 | u.asBits.payload = 0; |
467 | } |
468 | |
469 | inline JSValue::JSValue(JSTrueTag) |
470 | { |
471 | u.asBits.tag = TrueTag; |
472 | u.asBits.payload = 0; |
473 | } |
474 | |
475 | inline JSValue::JSValue(JSFalseTag) |
476 | { |
477 | u.asBits.tag = FalseTag; |
478 | u.asBits.payload = 0; |
479 | } |
480 | |
481 | inline JSValue::JSValue(HashTableDeletedValueTag) |
482 | { |
483 | u.asBits.tag = DeletedValueTag; |
484 | u.asBits.payload = 0; |
485 | } |
486 | |
487 | inline JSValue::JSValue(JSCell* ptr) |
488 | { |
489 | if (ptr) |
490 | u.asBits.tag = CellTag; |
491 | else |
492 | u.asBits.tag = EmptyValueTag; |
493 | u.asBits.payload = reinterpret_cast<int32_t>(ptr); |
494 | #if ENABLE(JSC_ZOMBIES) |
495 | ASSERT(!isZombie()); |
496 | #endif |
497 | } |
498 | |
499 | inline JSValue::JSValue(const JSCell* ptr) |
500 | { |
501 | if (ptr) |
502 | u.asBits.tag = CellTag; |
503 | else |
504 | u.asBits.tag = EmptyValueTag; |
505 | u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); |
506 | #if ENABLE(JSC_ZOMBIES) |
507 | ASSERT(!isZombie()); |
508 | #endif |
509 | } |
510 | |
511 | inline JSValue::operator bool() const |
512 | { |
513 | ASSERT(tag() != DeletedValueTag); |
514 | return tag() != EmptyValueTag; |
515 | } |
516 | |
517 | inline bool JSValue::operator==(const JSValue& other) const |
518 | { |
519 | return u.asEncodedJSValue == other.u.asEncodedJSValue; |
520 | } |
521 | |
522 | inline bool JSValue::operator!=(const JSValue& other) const |
523 | { |
524 | return u.asEncodedJSValue != other.u.asEncodedJSValue; |
525 | } |
526 | |
527 | inline bool JSValue::isUndefined() const |
528 | { |
529 | return tag() == UndefinedTag; |
530 | } |
531 | |
532 | inline bool JSValue::isNull() const |
533 | { |
534 | return tag() == NullTag; |
535 | } |
536 | |
537 | inline bool JSValue::isUndefinedOrNull() const |
538 | { |
539 | return isUndefined() || isNull(); |
540 | } |
541 | |
542 | inline bool JSValue::isCell() const |
543 | { |
544 | return tag() == CellTag; |
545 | } |
546 | |
547 | inline bool JSValue::isInt32() const |
548 | { |
549 | return tag() == Int32Tag; |
550 | } |
551 | |
552 | inline bool JSValue::isUInt32() const |
553 | { |
554 | return tag() == Int32Tag && asInt32() > -1; |
555 | } |
556 | |
557 | inline bool JSValue::isDouble() const |
558 | { |
559 | return tag() < LowestTag; |
560 | } |
561 | |
562 | inline bool JSValue::isTrue() const |
563 | { |
564 | return tag() == TrueTag; |
565 | } |
566 | |
567 | inline bool JSValue::isFalse() const |
568 | { |
569 | return tag() == FalseTag; |
570 | } |
571 | |
572 | inline uint32_t JSValue::tag() const |
573 | { |
574 | return u.asBits.tag; |
575 | } |
576 | |
577 | inline int32_t JSValue::payload() const |
578 | { |
579 | return u.asBits.payload; |
580 | } |
581 | |
582 | inline int32_t JSValue::asInt32() const |
583 | { |
584 | ASSERT(isInt32()); |
585 | return u.asBits.payload; |
586 | } |
587 | |
588 | inline uint32_t JSValue::asUInt32() const |
589 | { |
590 | ASSERT(isUInt32()); |
591 | return u.asBits.payload; |
592 | } |
593 | |
594 | inline double JSValue::asDouble() const |
595 | { |
596 | ASSERT(isDouble()); |
597 | return u.asDouble; |
598 | } |
599 | |
600 | ALWAYS_INLINE JSCell* JSValue::asCell() const |
601 | { |
602 | ASSERT(isCell()); |
603 | return reinterpret_cast<JSCell*>(u.asBits.payload); |
604 | } |
605 | |
606 | ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d) |
607 | { |
608 | u.asDouble = d; |
609 | } |
610 | |
611 | inline JSValue::JSValue(ExecState* exec, double d) |
612 | { |
613 | const int32_t asInt32 = static_cast<int32_t>(d); |
614 | if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0 |
615 | u.asDouble = d; |
616 | return; |
617 | } |
618 | *this = JSValue(exec, static_cast<int32_t>(d)); |
619 | } |
620 | |
621 | inline JSValue::JSValue(ExecState* exec, char i) |
622 | { |
623 | *this = JSValue(exec, static_cast<int32_t>(i)); |
624 | } |
625 | |
626 | inline JSValue::JSValue(ExecState* exec, unsigned char i) |
627 | { |
628 | *this = JSValue(exec, static_cast<int32_t>(i)); |
629 | } |
630 | |
631 | inline JSValue::JSValue(ExecState* exec, short i) |
632 | { |
633 | *this = JSValue(exec, static_cast<int32_t>(i)); |
634 | } |
635 | |
636 | inline JSValue::JSValue(ExecState* exec, unsigned short i) |
637 | { |
638 | *this = JSValue(exec, static_cast<int32_t>(i)); |
639 | } |
640 | |
641 | inline JSValue::JSValue(ExecState*, int i) |
642 | { |
643 | u.asBits.tag = Int32Tag; |
644 | u.asBits.payload = i; |
645 | } |
646 | |
647 | inline JSValue::JSValue(ExecState* exec, unsigned i) |
648 | { |
649 | if (static_cast<int32_t>(i) < 0) { |
650 | *this = JSValue(exec, static_cast<double>(i)); |
651 | return; |
652 | } |
653 | *this = JSValue(exec, static_cast<int32_t>(i)); |
654 | } |
655 | |
656 | inline JSValue::JSValue(ExecState* exec, long i) |
657 | { |
658 | if (static_cast<int32_t>(i) != i) { |
659 | *this = JSValue(exec, static_cast<double>(i)); |
660 | return; |
661 | } |
662 | *this = JSValue(exec, static_cast<int32_t>(i)); |
663 | } |
664 | |
665 | inline JSValue::JSValue(ExecState* exec, unsigned long i) |
666 | { |
667 | if (static_cast<uint32_t>(i) != i) { |
668 | *this = JSValue(exec, static_cast<double>(i)); |
669 | return; |
670 | } |
671 | *this = JSValue(exec, static_cast<uint32_t>(i)); |
672 | } |
673 | |
674 | inline JSValue::JSValue(ExecState* exec, long long i) |
675 | { |
676 | if (static_cast<int32_t>(i) != i) { |
677 | *this = JSValue(exec, static_cast<double>(i)); |
678 | return; |
679 | } |
680 | *this = JSValue(exec, static_cast<int32_t>(i)); |
681 | } |
682 | |
683 | inline JSValue::JSValue(ExecState* exec, unsigned long long i) |
684 | { |
685 | if (static_cast<uint32_t>(i) != i) { |
686 | *this = JSValue(exec, static_cast<double>(i)); |
687 | return; |
688 | } |
689 | *this = JSValue(exec, static_cast<uint32_t>(i)); |
690 | } |
691 | |
692 | inline JSValue::JSValue(JSGlobalData* globalData, double d) |
693 | { |
694 | const int32_t asInt32 = static_cast<int32_t>(d); |
695 | if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0 |
696 | u.asDouble = d; |
697 | return; |
698 | } |
699 | *this = JSValue(globalData, static_cast<int32_t>(d)); |
700 | } |
701 | |
702 | inline JSValue::JSValue(JSGlobalData*, int i) |
703 | { |
704 | u.asBits.tag = Int32Tag; |
705 | u.asBits.payload = i; |
706 | } |
707 | |
708 | inline JSValue::JSValue(JSGlobalData* globalData, unsigned i) |
709 | { |
710 | if (static_cast<int32_t>(i) < 0) { |
711 | *this = JSValue(globalData, static_cast<double>(i)); |
712 | return; |
713 | } |
714 | *this = JSValue(globalData, static_cast<int32_t>(i)); |
715 | } |
716 | |
717 | inline bool JSValue::isNumber() const |
718 | { |
719 | return isInt32() || isDouble(); |
720 | } |
721 | |
722 | inline bool JSValue::isBoolean() const |
723 | { |
724 | return isTrue() || isFalse(); |
725 | } |
726 | |
727 | inline bool JSValue::getBoolean(bool& v) const |
728 | { |
729 | if (isTrue()) { |
730 | v = true; |
731 | return true; |
732 | } |
733 | if (isFalse()) { |
734 | v = false; |
735 | return true; |
736 | } |
737 | |
738 | return false; |
739 | } |
740 | |
741 | inline bool JSValue::getBoolean() const |
742 | { |
743 | ASSERT(isBoolean()); |
744 | return tag() == TrueTag; |
745 | } |
746 | |
747 | inline double JSValue::uncheckedGetNumber() const |
748 | { |
749 | ASSERT(isNumber()); |
750 | return isInt32() ? asInt32() : asDouble(); |
751 | } |
752 | |
753 | ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const |
754 | { |
755 | return isNumber() ? asValue() : jsNumber(exec, this->toNumber(exec)); |
756 | } |
757 | |
758 | inline bool JSValue::getNumber(double& result) const |
759 | { |
760 | if (isInt32()) { |
761 | result = asInt32(); |
762 | return true; |
763 | } |
764 | if (isDouble()) { |
765 | result = asDouble(); |
766 | return true; |
767 | } |
768 | return false; |
769 | } |
770 | |
771 | #else // USE(JSVALUE32_64) |
772 | |
773 | // JSValue member functions. |
774 | inline EncodedJSValue JSValue::encode(JSValue value) |
775 | { |
776 | EncodedJSValue r; |
777 | memcpy(dest: &r, src: &value.m_ptr, n: sizeof(r)); |
778 | return r; |
779 | } |
780 | |
781 | inline JSValue JSValue::decode(EncodedJSValue ptr) |
782 | { |
783 | JSCell *cellPtr; |
784 | memcpy(dest: &cellPtr, src: &ptr, n: sizeof(cellPtr)); |
785 | return JSValue(cellPtr); |
786 | } |
787 | |
788 | inline JSValue JSValue::makeImmediate(intptr_t value) |
789 | { |
790 | JSCell *cellPtr; |
791 | memcpy(dest: &cellPtr, src: &value, n: sizeof(cellPtr)); |
792 | return JSValue(cellPtr); |
793 | } |
794 | |
795 | inline intptr_t JSValue::immediateValue() |
796 | { |
797 | intptr_t v; |
798 | memcpy(dest: &v, src: &m_ptr, n: sizeof(v)); |
799 | return v; |
800 | } |
801 | |
802 | // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. |
803 | inline JSValue::JSValue() |
804 | : m_ptr(0) |
805 | { |
806 | } |
807 | |
808 | // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. |
809 | inline JSValue::JSValue(HashTableDeletedValueTag) |
810 | : m_ptr(reinterpret_cast<JSCell*>(0x4)) |
811 | { |
812 | } |
813 | |
814 | inline JSValue::JSValue(JSCell* ptr) |
815 | : m_ptr(ptr) |
816 | { |
817 | #if ENABLE(JSC_ZOMBIES) |
818 | ASSERT(!isZombie()); |
819 | #endif |
820 | } |
821 | |
822 | inline JSValue::JSValue(const JSCell* ptr) |
823 | : m_ptr(const_cast<JSCell*>(ptr)) |
824 | { |
825 | #if ENABLE(JSC_ZOMBIES) |
826 | ASSERT(!isZombie()); |
827 | #endif |
828 | } |
829 | |
830 | inline JSValue::operator bool() const |
831 | { |
832 | return m_ptr; |
833 | } |
834 | |
835 | inline bool JSValue::operator==(const JSValue& other) const |
836 | { |
837 | return m_ptr == other.m_ptr; |
838 | } |
839 | |
840 | inline bool JSValue::operator!=(const JSValue& other) const |
841 | { |
842 | return m_ptr != other.m_ptr; |
843 | } |
844 | |
845 | inline bool JSValue::isUndefined() const |
846 | { |
847 | return asValue() == jsUndefined(); |
848 | } |
849 | |
850 | inline bool JSValue::isNull() const |
851 | { |
852 | return asValue() == jsNull(); |
853 | } |
854 | #endif // USE(JSVALUE32_64) |
855 | |
856 | } // namespace JSC |
857 | |
858 | #endif // JSValue_h |
859 | |