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 #include <wtf/StdLibExtras.h> 34 35 namespace JSC { 36 37 extern const double NaN; 38 extern const double Inf; 39 40 class ExecState; 41 class Identifier; 42 class JSCell; 43 class JSGlobalData; 44 class JSGlobalObject; 45 class JSObject; 46 class JSString; 47 class PropertySlot; 48 class PutPropertySlot; 49 class UString; 50 51 struct ClassInfo; 52 struct Instruction; 53 54 template <class T> class WriteBarrierBase; 55 56 enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; 57 58 59 #if USE(JSVALUE32_64) 60 typedef int64_t EncodedJSValue; 61 #else 62 typedef void* EncodedJSValue; 63 #endif 64 65 union EncodedValueDescriptor { 66 int64_t asInt64; 67 #if USE(JSVALUE32_64) 68 double asDouble; 69 #elif USE(JSVALUE64) 70 JSCell* ptr; 71 #endif 72 73 #if CPU(BIG_ENDIAN) 74 struct { 75 int32_t tag; 76 int32_t payload; 77 } asBits; 78 #else 79 struct { 80 int32_t payload; 81 int32_t tag; 82 } asBits; 83 #endif 84 }; 85 86 double nonInlineNaN(); 87 88 // This implements ToInt32, defined in ECMA-262 9.5. 89 int32_t toInt32(double); 90 91 // This implements ToUInt32, defined in ECMA-262 9.6. toUInt32(double number)92 inline uint32_t toUInt32(double number) 93 { 94 // As commented in the spec, the operation of ToInt32 and ToUint32 only differ 95 // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6. 96 return toInt32(number); 97 } 98 99 class JSValue { 100 friend struct EncodedJSValueHashTraits; 101 friend class JIT; 102 friend class JITStubs; 103 friend class JITStubCall; 104 friend class JSInterfaceJIT; 105 friend class SpecializedThunkJIT; 106 107 public: 108 static EncodedJSValue encode(JSValue); 109 static JSValue decode(EncodedJSValue); 110 111 enum JSNullTag { JSNull }; 112 enum JSUndefinedTag { JSUndefined }; 113 enum JSTrueTag { JSTrue }; 114 enum JSFalseTag { JSFalse }; 115 enum EncodeAsDoubleTag { EncodeAsDouble }; 116 117 JSValue(); 118 JSValue(JSNullTag); 119 JSValue(JSUndefinedTag); 120 JSValue(JSTrueTag); 121 JSValue(JSFalseTag); 122 JSValue(JSCell* ptr); 123 JSValue(const JSCell* ptr); 124 125 // Numbers 126 JSValue(EncodeAsDoubleTag, double); 127 explicit JSValue(double); 128 explicit JSValue(char); 129 explicit JSValue(unsigned char); 130 explicit JSValue(short); 131 explicit JSValue(unsigned short); 132 explicit JSValue(int); 133 explicit JSValue(unsigned); 134 explicit JSValue(long); 135 explicit JSValue(unsigned long); 136 explicit JSValue(long long); 137 explicit JSValue(unsigned long long); 138 139 operator bool() const; 140 bool operator==(const JSValue& other) const; 141 bool operator!=(const JSValue& other) const; 142 143 bool isInt32() const; 144 bool isUInt32() const; 145 bool isDouble() const; 146 bool isTrue() const; 147 bool isFalse() const; 148 149 int32_t asInt32() const; 150 uint32_t asUInt32() const; 151 double asDouble() const; 152 153 // Querying the type. 154 bool isUndefined() const; 155 bool isNull() const; 156 bool isUndefinedOrNull() const; 157 bool isBoolean() const; 158 bool isNumber() const; 159 bool isString() const; 160 bool isGetterSetter() const; 161 bool isObject() const; 162 bool inherits(const ClassInfo*) const; 163 164 // Extracting the value. 165 bool getBoolean(bool&) const; 166 bool getBoolean() const; // false if not a boolean 167 bool getNumber(double&) const; 168 double uncheckedGetNumber() const; 169 bool getString(ExecState* exec, UString&) const; 170 UString getString(ExecState* exec) const; // null string if not a string 171 JSObject* getObject() const; // 0 if not an object 172 173 // Extracting integer values. 174 bool getUInt32(uint32_t&) const; 175 176 // Basic conversions. 177 JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; 178 bool getPrimitiveNumber(ExecState*, double& number, JSValue&); 179 180 bool toBoolean(ExecState*) const; 181 182 // toNumber conversion is expected to be side effect free if an exception has 183 // been set in the ExecState already. 184 double toNumber(ExecState*) const; 185 JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number. 186 UString toString(ExecState*) const; 187 UString toPrimitiveString(ExecState*) const; 188 JSObject* toObject(ExecState*) const; 189 JSObject* toObject(ExecState*, JSGlobalObject*) const; 190 191 // Integer conversions. 192 double toInteger(ExecState*) const; 193 double toIntegerPreserveNaN(ExecState*) const; 194 int32_t toInt32(ExecState*) const; 195 uint32_t toUInt32(ExecState*) const; 196 197 #if ENABLE(JSC_ZOMBIES) 198 bool isZombie() const; 199 #endif 200 201 // Floating point conversions (this is a convenience method for webcore; 202 // signle precision float is not a representation used in JS or JSC). toFloat(ExecState * exec)203 float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } 204 205 // Object operations, with the toObject operation included. 206 JSValue get(ExecState*, const Identifier& propertyName) const; 207 JSValue get(ExecState*, const Identifier& propertyName, PropertySlot&) const; 208 JSValue get(ExecState*, unsigned propertyName) const; 209 JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; 210 void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); 211 void putDirect(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); 212 void put(ExecState*, unsigned propertyName, JSValue); 213 214 bool needsThisConversion() const; 215 JSObject* toThisObject(ExecState*) const; 216 JSValue toStrictThisObject(ExecState*) const; 217 UString toThisString(ExecState*) const; 218 JSString* toThisJSString(ExecState*) const; 219 220 static bool equal(ExecState* exec, JSValue v1, JSValue v2); 221 static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); 222 static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); 223 static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); 224 static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); 225 static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); 226 227 JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object 228 229 bool isCell() const; 230 JSCell* asCell() const; 231 bool isValidCallee(); 232 233 #ifndef NDEBUG 234 char* description(); 235 #endif 236 237 private: 238 template <class T> JSValue(WriteBarrierBase<T>); 239 240 enum HashTableDeletedValueTag { HashTableDeletedValue }; 241 JSValue(HashTableDeletedValueTag); 242 asValue()243 inline const JSValue asValue() const { return *this; } 244 JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; 245 JSObject* toThisObjectSlowCase(ExecState*) const; 246 247 JSObject* synthesizePrototype(ExecState*) const; 248 JSObject* synthesizeObject(ExecState*) const; 249 250 #if USE(JSVALUE32_64) 251 /* 252 * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded 253 * form for immediates. 254 * 255 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value 256 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values 257 * can encode a 51-bit payload. Hardware produced and C-library payloads typically 258 * have a payload of zero. We assume that non-zero payloads are available to encode 259 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are 260 * all set represents a NaN with a non-zero payload, we can use this space in the NaN 261 * ranges to encode other values (however there are also other ranges of NaN space that 262 * could have been selected). 263 * 264 * For JSValues that do not contain a double value, the high 32 bits contain the tag 265 * values listed in the enums below, which all correspond to NaN-space. In the case of 266 * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer 267 * integer or boolean value; in the case of all other tags the payload is 0. 268 */ 269 enum { Int32Tag = 0xffffffff }; 270 enum { BooleanTag = 0xfffffffe }; 271 enum { NullTag = 0xfffffffd }; 272 enum { UndefinedTag = 0xfffffffc }; 273 enum { CellTag = 0xfffffffb }; 274 enum { EmptyValueTag = 0xfffffffa }; 275 enum { DeletedValueTag = 0xfffffff9 }; 276 277 enum { LowestTag = DeletedValueTag }; 278 279 uint32_t tag() const; 280 int32_t payload() const; 281 #elif USE(JSVALUE64) 282 /* 283 * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded 284 * form for immediates. 285 * 286 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value 287 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values 288 * can encode a 51-bit payload. Hardware produced and C-library payloads typically 289 * have a payload of zero. We assume that non-zero payloads are available to encode 290 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are 291 * all set represents a NaN with a non-zero payload, we can use this space in the NaN 292 * ranges to encode other values (however there are also other ranges of NaN space that 293 * could have been selected). 294 * 295 * This range of NaN space is represented by 64-bit numbers begining with the 16-bit 296 * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision 297 * numbers will begin fall in these ranges. 298 * 299 * The top 16-bits denote the type of the encoded JSValue: 300 * 301 * Pointer { 0000:PPPP:PPPP:PPPP 302 * / 0001:****:****:**** 303 * Double { ... 304 * \ FFFE:****:****:**** 305 * Integer { FFFF:0000:IIII:IIII 306 * 307 * The scheme we have implemented encodes double precision values by performing a 308 * 64-bit integer addition of the value 2^48 to the number. After this manipulation 309 * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF. 310 * Values must be decoded by reversing this operation before subsequent floating point 311 * operations my be peformed. 312 * 313 * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. 314 * 315 * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean, 316 * null and undefined values are represented by specific, invalid pointer values: 317 * 318 * False: 0x06 319 * True: 0x07 320 * Undefined: 0x0a 321 * Null: 0x02 322 * 323 * These values have the following properties: 324 * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be 325 * quickly distinguished from all immediate values, including these invalid pointers. 326 * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the 327 * same value, allowing null & undefined to be quickly detected. 328 * 329 * No valid JSValue will have the bit pattern 0x0, this is used to represent array 330 * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0). 331 */ 332 333 // These values are #defines since using static const integers here is a ~1% regression! 334 335 // This value is 2^48, used to encode doubles such that the encoded value will begin 336 // with a 16-bit pattern within the range 0x0001..0xFFFE. 337 #define DoubleEncodeOffset 0x1000000000000ll 338 // If all bits in the mask are set, this indicates an integer number, 339 // if any but not all are set this value is a double precision number. 340 #define TagTypeNumber 0xffff000000000000ll 341 342 // All non-numeric (bool, null, undefined) immediates have bit 2 set. 343 #define TagBitTypeOther 0x2ll 344 #define TagBitBool 0x4ll 345 #define TagBitUndefined 0x8ll 346 // Combined integer value for non-numeric immediates. 347 #define ValueFalse (TagBitTypeOther | TagBitBool | false) 348 #define ValueTrue (TagBitTypeOther | TagBitBool | true) 349 #define ValueUndefined (TagBitTypeOther | TagBitUndefined) 350 #define ValueNull (TagBitTypeOther) 351 352 // TagMask is used to check for all types of immediate values (either number or 'other'). 353 #define TagMask (TagTypeNumber | TagBitTypeOther) 354 355 // These special values are never visible to JavaScript code; Empty is used to represent 356 // Array holes, and for uninitialized JSValues. Deleted is used in hash table code. 357 // These values would map to cell types in the JSValue encoding, but not valid GC cell 358 // pointer should have either of these values (Empty is null, deleted is at an invalid 359 // alignment for a GC cell, and in the zero page). 360 #define ValueEmpty 0x0ll 361 #define ValueDeleted 0x4ll 362 #endif 363 364 EncodedValueDescriptor u; 365 }; 366 367 #if USE(JSVALUE32_64) 368 typedef IntHash<EncodedJSValue> EncodedJSValueHash; 369 370 struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { 371 static const bool emptyValueIsZero = false; emptyValueEncodedJSValueHashTraits372 static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); } constructDeletedValueEncodedJSValueHashTraits373 static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } isDeletedValueEncodedJSValueHashTraits374 static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } 375 }; 376 #else 377 typedef PtrHash<EncodedJSValue> EncodedJSValueHash; 378 379 struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { constructDeletedValueEncodedJSValueHashTraits380 static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } isDeletedValueEncodedJSValueHashTraits381 static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } 382 }; 383 #endif 384 385 // Stand-alone helper functions. jsNull()386 inline JSValue jsNull() 387 { 388 return JSValue(JSValue::JSNull); 389 } 390 jsUndefined()391 inline JSValue jsUndefined() 392 { 393 return JSValue(JSValue::JSUndefined); 394 } 395 jsBoolean(bool b)396 inline JSValue jsBoolean(bool b) 397 { 398 return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); 399 } 400 jsDoubleNumber(double d)401 ALWAYS_INLINE JSValue jsDoubleNumber(double d) 402 { 403 return JSValue(JSValue::EncodeAsDouble, d); 404 } 405 jsNumber(double d)406 ALWAYS_INLINE JSValue jsNumber(double d) 407 { 408 return JSValue(d); 409 } 410 jsNumber(char i)411 ALWAYS_INLINE JSValue jsNumber(char i) 412 { 413 return JSValue(i); 414 } 415 jsNumber(unsigned char i)416 ALWAYS_INLINE JSValue jsNumber(unsigned char i) 417 { 418 return JSValue(i); 419 } 420 jsNumber(short i)421 ALWAYS_INLINE JSValue jsNumber(short i) 422 { 423 return JSValue(i); 424 } 425 jsNumber(unsigned short i)426 ALWAYS_INLINE JSValue jsNumber(unsigned short i) 427 { 428 return JSValue(i); 429 } 430 jsNumber(int i)431 ALWAYS_INLINE JSValue jsNumber(int i) 432 { 433 return JSValue(i); 434 } 435 jsNumber(unsigned i)436 ALWAYS_INLINE JSValue jsNumber(unsigned i) 437 { 438 return JSValue(i); 439 } 440 jsNumber(long i)441 ALWAYS_INLINE JSValue jsNumber(long i) 442 { 443 return JSValue(i); 444 } 445 jsNumber(unsigned long i)446 ALWAYS_INLINE JSValue jsNumber(unsigned long i) 447 { 448 return JSValue(i); 449 } 450 jsNumber(long long i)451 ALWAYS_INLINE JSValue jsNumber(long long i) 452 { 453 return JSValue(i); 454 } 455 jsNumber(unsigned long long i)456 ALWAYS_INLINE JSValue jsNumber(unsigned long long i) 457 { 458 return JSValue(i); 459 } 460 461 inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); } 462 inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; } 463 464 inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); } 465 inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; } 466 467 bool isZombie(const JSCell*); 468 469 } // namespace JSC 470 471 #endif // JSValue_h 472