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