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, 2012, 2015 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 JSCJSValue_h
24#define JSCJSValue_h
25
26#include "JSExportMacros.h"
27#include "PureNaN.h"
28#include <functional>
29#include <math.h>
30#include <stddef.h>
31#include <stdint.h>
32#include <wtf/Assertions.h>
33#include <wtf/Forward.h>
34#include <wtf/HashMap.h>
35#include <wtf/HashTraits.h>
36#include <wtf/MathExtras.h>
37#include <wtf/MediaTime.h>
38#include <wtf/StdLibExtras.h>
39#include <wtf/TriState.h>
40
41namespace JSC {
42
43class AssemblyHelpers;
44class ExecState;
45class JSCell;
46class JSValueSource;
47class VM;
48class JSGlobalObject;
49class JSObject;
50class JSString;
51class Identifier;
52class PropertyName;
53class PropertySlot;
54class PutPropertySlot;
55class Structure;
56#if ENABLE(DFG_JIT)
57namespace DFG {
58class JITCompiler;
59class OSRExitCompiler;
60class SpeculativeJIT;
61}
62#endif
63#if !ENABLE(JIT)
64namespace LLInt {
65class CLoop;
66}
67#endif
68
69struct ClassInfo;
70struct DumpContext;
71struct Instruction;
72struct MethodTable;
73
74template <class T> class WriteBarrierBase;
75
76enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString };
77enum ECMAMode { StrictMode, NotStrictMode };
78
79typedef int64_t EncodedJSValue;
80
81union EncodedValueDescriptor {
82 int64_t asInt64;
83#if USE(JSVALUE32_64)
84 double asDouble;
85#elif USE(JSVALUE64)
86 JSCell* ptr;
87#endif
88
89#if CPU(BIG_ENDIAN)
90 struct {
91 int32_t tag;
92 int32_t payload;
93 } asBits;
94#else
95 struct {
96 int32_t payload;
97 int32_t tag;
98 } asBits;
99#endif
100};
101
102#define TagOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))
103#define PayloadOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))
104
105#if USE(JSVALUE64)
106#define CellPayloadOffset 0
107#else
108#define CellPayloadOffset PayloadOffset
109#endif
110
111enum WhichValueWord {
112 TagWord,
113 PayloadWord
114};
115
116// This implements ToInt32, defined in ECMA-262 9.5.
117JS_EXPORT_PRIVATE int32_t toInt32(double);
118
119// This implements ToUInt32, defined in ECMA-262 9.6.
120inline uint32_t toUInt32(double number)
121{
122 // As commented in the spec, the operation of ToInt32 and ToUint32 only differ
123 // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6.
124 return toInt32(number);
125}
126
127int64_t tryConvertToInt52(double);
128bool isInt52(double);
129
130enum class SourceCodeRepresentation {
131 Other,
132 Integer,
133 Double
134};
135
136class JSValue {
137 friend struct EncodedJSValueHashTraits;
138 friend struct EncodedJSValueWithRepresentationHashTraits;
139 friend class AssemblyHelpers;
140 friend class JIT;
141 friend class JITSlowPathCall;
142 friend class JITStubs;
143 friend class JITStubCall;
144 friend class JSInterfaceJIT;
145 friend class JSValueSource;
146 friend class SpecializedThunkJIT;
147#if ENABLE(DFG_JIT)
148 friend class DFG::JITCompiler;
149 friend class DFG::OSRExitCompiler;
150 friend class DFG::SpeculativeJIT;
151#endif
152#if !ENABLE(JIT)
153 friend class LLInt::CLoop;
154#endif
155
156public:
157#if USE(JSVALUE32_64)
158 enum { Int32Tag = 0xffffffff };
159 enum { BooleanTag = 0xfffffffe };
160 enum { NullTag = 0xfffffffd };
161 enum { UndefinedTag = 0xfffffffc };
162 enum { CellTag = 0xfffffffb };
163 enum { EmptyValueTag = 0xfffffffa };
164 enum { DeletedValueTag = 0xfffffff9 };
165
166 enum { LowestTag = DeletedValueTag };
167#endif
168
169 static EncodedJSValue encode(JSValue);
170 static JSValue decode(EncodedJSValue);
171
172 enum JSNullTag { JSNull };
173 enum JSUndefinedTag { JSUndefined };
174 enum JSTrueTag { JSTrue };
175 enum JSFalseTag { JSFalse };
176 enum EncodeAsDoubleTag { EncodeAsDouble };
177
178 JSValue();
179 JSValue(JSNullTag);
180 JSValue(JSUndefinedTag);
181 JSValue(JSTrueTag);
182 JSValue(JSFalseTag);
183 JSValue(JSCell* ptr);
184 JSValue(const JSCell* ptr);
185
186 // Numbers
187 JSValue(EncodeAsDoubleTag, double);
188 explicit JSValue(double);
189 explicit JSValue(char);
190 explicit JSValue(unsigned char);
191 explicit JSValue(short);
192 explicit JSValue(unsigned short);
193 explicit JSValue(int);
194 explicit JSValue(unsigned);
195 explicit JSValue(long);
196 explicit JSValue(unsigned long);
197 explicit JSValue(long long);
198 explicit JSValue(unsigned long long);
199
200 explicit operator bool() const;
201 bool operator==(const JSValue& other) const;
202 bool operator!=(const JSValue& other) const;
203
204 bool isInt32() const;
205 bool isUInt32() const;
206 bool isDouble() const;
207 bool isTrue() const;
208 bool isFalse() const;
209
210 int32_t asInt32() const;
211 uint32_t asUInt32() const;
212 int64_t asMachineInt() const;
213 double asDouble() const;
214 bool asBoolean() const;
215 double asNumber() const;
216
217 int32_t asInt32ForArithmetic() const; // Boolean becomes an int, but otherwise like asInt32().
218
219 // Querying the type.
220 bool isEmpty() const;
221 bool isFunction() const;
222 bool isConstructor() const;
223 bool isUndefined() const;
224 bool isNull() const;
225 bool isUndefinedOrNull() const;
226 bool isBoolean() const;
227 bool isMachineInt() const;
228 bool isNumber() const;
229 bool isString() const;
230 bool isSymbol() const;
231 bool isPrimitive() const;
232 bool isGetterSetter() const;
233 bool isCustomGetterSetter() const;
234 bool isObject() const;
235 bool inherits(const ClassInfo*) const;
236
237 // Extracting the value.
238 bool getString(ExecState*, WTF::String&) const;
239 WTF::String getString(ExecState*) const; // null string if not a string
240 JSObject* getObject() const; // 0 if not an object
241
242 // Extracting integer values.
243 bool getUInt32(uint32_t&) const;
244
245 // Basic conversions.
246 JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
247 bool getPrimitiveNumber(ExecState*, double& number, JSValue&);
248
249 bool toBoolean(ExecState*) const;
250 TriState pureToBoolean() const;
251
252 // toNumber conversion is expected to be side effect free if an exception has
253 // been set in the ExecState already.
254 double toNumber(ExecState*) const;
255 JSString* toString(ExecState*) const; // On exception, this returns the empty string.
256 JSString* toStringOrNull(ExecState*) const; // On exception, this returns null, to make exception checks faster.
257 Identifier toPropertyKey(ExecState*) const;
258 WTF::String toWTFString(ExecState*) const;
259 JSObject* toObject(ExecState*) const;
260 JSObject* toObject(ExecState*, JSGlobalObject*) const;
261
262 // Integer conversions.
263 JS_EXPORT_PRIVATE double toInteger(ExecState*) const;
264 JS_EXPORT_PRIVATE double toIntegerPreserveNaN(ExecState*) const;
265 int32_t toInt32(ExecState*) const;
266 uint32_t toUInt32(ExecState*) const;
267 double toLength(ExecState*) const;
268
269 // Floating point conversions (this is a convenience function for WebCore;
270 // single precision float is not a representation used in JS or JSC).
271 float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); }
272
273 // Object operations, with the toObject operation included.
274 JSValue get(ExecState*, PropertyName) const;
275 JSValue get(ExecState*, PropertyName, PropertySlot&) const;
276 JSValue get(ExecState*, unsigned propertyName) const;
277 JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
278
279 bool getPropertySlot(ExecState*, PropertyName, PropertySlot&) const;
280
281 void put(ExecState*, PropertyName, JSValue, PutPropertySlot&);
282 void putInline(ExecState*, PropertyName, JSValue, PutPropertySlot&);
283 JS_EXPORT_PRIVATE void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&);
284 JS_EXPORT_PRIVATE void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
285 void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
286
287 JSValue toThis(ExecState*, ECMAMode) const;
288
289 static bool equal(ExecState*, JSValue v1, JSValue v2);
290 static bool equalSlowCase(ExecState*, JSValue v1, JSValue v2);
291 static bool equalSlowCaseInline(ExecState*, JSValue v1, JSValue v2);
292 static bool strictEqual(ExecState*, JSValue v1, JSValue v2);
293 static bool strictEqualSlowCase(ExecState*, JSValue v1, JSValue v2);
294 static bool strictEqualSlowCaseInline(ExecState*, JSValue v1, JSValue v2);
295 static TriState pureStrictEqual(JSValue v1, JSValue v2);
296
297 bool isCell() const;
298 JSCell* asCell() const;
299 JS_EXPORT_PRIVATE bool isValidCallee();
300
301 JSValue structureOrUndefined() const;
302
303 JS_EXPORT_PRIVATE void dump(PrintStream&) const;
304 void dumpInContext(PrintStream&, DumpContext*) const;
305 void dumpInContextAssumingStructure(PrintStream&, DumpContext*, Structure*) const;
306 void dumpForBacktrace(PrintStream&) const;
307
308 JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const;
309 bool requireObjectCoercible(ExecState*) const;
310
311 // Constants used for Int52. Int52 isn't part of JSValue right now, but JSValues may be
312 // converted to Int52s and back again.
313 static const unsigned numberOfInt52Bits = 52;
314 static const int64_t notInt52 = static_cast<int64_t>(1) << numberOfInt52Bits;
315 static const unsigned int52ShiftAmount = 12;
316
317 static ptrdiff_t offsetOfPayload() { return OBJECT_OFFSETOF(JSValue, u.asBits.payload); }
318 static ptrdiff_t offsetOfTag() { return OBJECT_OFFSETOF(JSValue, u.asBits.tag); }
319
320#if USE(JSVALUE32_64)
321 /*
322 * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
323 * form for immediates.
324 *
325 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
326 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
327 * can encode a 51-bit payload. Hardware produced and C-library payloads typically
328 * have a payload of zero. We assume that non-zero payloads are available to encode
329 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
330 * all set represents a NaN with a non-zero payload, we can use this space in the NaN
331 * ranges to encode other values (however there are also other ranges of NaN space that
332 * could have been selected).
333 *
334 * For JSValues that do not contain a double value, the high 32 bits contain the tag
335 * values listed in the enums below, which all correspond to NaN-space. In the case of
336 * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer
337 * integer or boolean value; in the case of all other tags the payload is 0.
338 */
339 uint32_t tag() const;
340 int32_t payload() const;
341
342#if !ENABLE(JIT)
343 // This should only be used by the LLInt C Loop interpreter who needs
344 // synthesize JSValue from its "register"s holding tag and payload
345 // values.
346 explicit JSValue(int32_t tag, int32_t payload);
347#endif
348
349#elif USE(JSVALUE64)
350 /*
351 * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
352 * form for immediates.
353 *
354 * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
355 * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
356 * can encode a 51-bit payload. Hardware produced and C-library payloads typically
357 * have a payload of zero. We assume that non-zero payloads are available to encode
358 * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
359 * all set represents a NaN with a non-zero payload, we can use this space in the NaN
360 * ranges to encode other values (however there are also other ranges of NaN space that
361 * could have been selected).
362 *
363 * This range of NaN space is represented by 64-bit numbers begining with the 16-bit
364 * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
365 * numbers will fall in these ranges.
366 *
367 * The top 16-bits denote the type of the encoded JSValue:
368 *
369 * Pointer { 0000:PPPP:PPPP:PPPP
370 * / 0001:****:****:****
371 * Double { ...
372 * \ FFFE:****:****:****
373 * Integer { FFFF:0000:IIII:IIII
374 *
375 * The scheme we have implemented encodes double precision values by performing a
376 * 64-bit integer addition of the value 2^48 to the number. After this manipulation
377 * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
378 * Values must be decoded by reversing this operation before subsequent floating point
379 * operations may be peformed.
380 *
381 * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
382 *
383 * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean,
384 * null and undefined values are represented by specific, invalid pointer values:
385 *
386 * False: 0x06
387 * True: 0x07
388 * Undefined: 0x0a
389 * Null: 0x02
390 *
391 * These values have the following properties:
392 * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be
393 * quickly distinguished from all immediate values, including these invalid pointers.
394 * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
395 * same value, allowing null & undefined to be quickly detected.
396 *
397 * No valid JSValue will have the bit pattern 0x0, this is used to represent array
398 * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
399 */
400
401 // These values are #defines since using static const integers here is a ~1% regression!
402
403 // This value is 2^48, used to encode doubles such that the encoded value will begin
404 // with a 16-bit pattern within the range 0x0001..0xFFFE.
405 #define DoubleEncodeOffset 0x1000000000000ll
406 // If all bits in the mask are set, this indicates an integer number,
407 // if any but not all are set this value is a double precision number.
408 #define TagTypeNumber 0xffff000000000000ll
409
410 // All non-numeric (bool, null, undefined) immediates have bit 2 set.
411 #define TagBitTypeOther 0x2ll
412 #define TagBitBool 0x4ll
413 #define TagBitUndefined 0x8ll
414 // Combined integer value for non-numeric immediates.
415 #define ValueFalse (TagBitTypeOther | TagBitBool | false)
416 #define ValueTrue (TagBitTypeOther | TagBitBool | true)
417 #define ValueUndefined (TagBitTypeOther | TagBitUndefined)
418 #define ValueNull (TagBitTypeOther)
419
420 // TagMask is used to check for all types of immediate values (either number or 'other').
421 #define TagMask (TagTypeNumber | TagBitTypeOther)
422
423 // These special values are never visible to JavaScript code; Empty is used to represent
424 // Array holes, and for uninitialized JSValues. Deleted is used in hash table code.
425 // These values would map to cell types in the JSValue encoding, but not valid GC cell
426 // pointer should have either of these values (Empty is null, deleted is at an invalid
427 // alignment for a GC cell, and in the zero page).
428 #define ValueEmpty 0x0ll
429 #define ValueDeleted 0x4ll
430#endif
431
432private:
433 template <class T> JSValue(WriteBarrierBase<T>);
434
435 enum HashTableDeletedValueTag { HashTableDeletedValue };
436 JSValue(HashTableDeletedValueTag);
437
438 inline const JSValue asValue() const { return *this; }
439 JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
440 JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*, bool returnEmptyStringOnError) const;
441 JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const;
442 JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
443 JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const;
444
445 EncodedValueDescriptor u;
446};
447
448typedef IntHash<EncodedJSValue> EncodedJSValueHash;
449
450#if USE(JSVALUE32_64)
451struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
452 static const bool emptyValueIsZero = false;
453 static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); }
454 static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
455 static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
456};
457#else
458struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
459 static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
460 static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
461};
462#endif
463
464typedef std::pair<EncodedJSValue, SourceCodeRepresentation> EncodedJSValueWithRepresentation;
465
466struct EncodedJSValueWithRepresentationHashTraits : HashTraits<EncodedJSValueWithRepresentation> {
467 static const bool emptyValueIsZero = false;
468 static EncodedJSValueWithRepresentation emptyValue() { return std::make_pair(JSValue::encode(JSValue()), SourceCodeRepresentation::Other); }
469 static void constructDeletedValue(EncodedJSValueWithRepresentation& slot) { slot = std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
470 static bool isDeletedValue(EncodedJSValueWithRepresentation value) { return value == std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
471};
472
473struct EncodedJSValueWithRepresentationHash {
474 static unsigned hash(const EncodedJSValueWithRepresentation& value)
475 {
476 return WTF::pairIntHash(EncodedJSValueHash::hash(value.first), IntHash<SourceCodeRepresentation>::hash(value.second));
477 }
478 static bool equal(const EncodedJSValueWithRepresentation& a, const EncodedJSValueWithRepresentation& b)
479 {
480 return a == b;
481 }
482 static const bool safeToCompareToEmptyOrDeleted = true;
483};
484
485// Stand-alone helper functions.
486inline JSValue jsNull()
487{
488 return JSValue(JSValue::JSNull);
489}
490
491inline JSValue jsUndefined()
492{
493 return JSValue(JSValue::JSUndefined);
494}
495
496inline JSValue jsTDZValue()
497{
498 return JSValue();
499}
500
501inline JSValue jsBoolean(bool b)
502{
503 return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse);
504}
505
506ALWAYS_INLINE JSValue jsDoubleNumber(double d)
507{
508 ASSERT(JSValue(JSValue::EncodeAsDouble, d).isNumber());
509 return JSValue(JSValue::EncodeAsDouble, d);
510}
511
512ALWAYS_INLINE JSValue jsNumber(double d)
513{
514 ASSERT(JSValue(d).isNumber());
515 return JSValue(d);
516}
517
518ALWAYS_INLINE JSValue jsNumber(MediaTime t)
519{
520 return jsNumber(t.toDouble());
521}
522
523ALWAYS_INLINE JSValue jsNumber(char i)
524{
525 return JSValue(i);
526}
527
528ALWAYS_INLINE JSValue jsNumber(unsigned char i)
529{
530 return JSValue(i);
531}
532
533ALWAYS_INLINE JSValue jsNumber(short i)
534{
535 return JSValue(i);
536}
537
538ALWAYS_INLINE JSValue jsNumber(unsigned short i)
539{
540 return JSValue(i);
541}
542
543ALWAYS_INLINE JSValue jsNumber(int i)
544{
545 return JSValue(i);
546}
547
548ALWAYS_INLINE JSValue jsNumber(unsigned i)
549{
550 return JSValue(i);
551}
552
553ALWAYS_INLINE JSValue jsNumber(long i)
554{
555 return JSValue(i);
556}
557
558ALWAYS_INLINE JSValue jsNumber(unsigned long i)
559{
560 return JSValue(i);
561}
562
563ALWAYS_INLINE JSValue jsNumber(long long i)
564{
565 return JSValue(i);
566}
567
568ALWAYS_INLINE JSValue jsNumber(unsigned long long i)
569{
570 return JSValue(i);
571}
572
573inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); }
574inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; }
575
576inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); }
577inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; }
578
579} // namespace JSC
580
581#endif // JSCJSValue_h
582