]>
Commit | Line | Data |
---|---|---|
93a37866 A |
1 | /* |
2 | * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #ifndef JSValueInlines_h | |
27 | #define JSValueInlines_h | |
28 | ||
29 | #include "InternalFunction.h" | |
30 | #include "JSCJSValue.h" | |
31 | #include "JSCellInlines.h" | |
32 | #include "JSFunction.h" | |
81345200 | 33 | #include <wtf/text/StringImpl.h> |
93a37866 A |
34 | |
35 | namespace JSC { | |
36 | ||
37 | ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const | |
38 | { | |
39 | if (isInt32()) | |
40 | return asInt32(); | |
41 | return JSC::toInt32(toNumber(exec)); | |
42 | } | |
43 | ||
44 | inline uint32_t JSValue::toUInt32(ExecState* exec) const | |
45 | { | |
46 | // See comment on JSC::toUInt32, above. | |
47 | return toInt32(exec); | |
48 | } | |
49 | ||
50 | inline bool JSValue::isUInt32() const | |
51 | { | |
52 | return isInt32() && asInt32() >= 0; | |
53 | } | |
54 | ||
55 | inline uint32_t JSValue::asUInt32() const | |
56 | { | |
57 | ASSERT(isUInt32()); | |
58 | return asInt32(); | |
59 | } | |
60 | ||
61 | inline double JSValue::asNumber() const | |
62 | { | |
63 | ASSERT(isNumber()); | |
64 | return isInt32() ? asInt32() : asDouble(); | |
65 | } | |
66 | ||
67 | inline JSValue jsNaN() | |
68 | { | |
81345200 | 69 | return JSValue(PNaN); |
93a37866 A |
70 | } |
71 | ||
72 | inline JSValue::JSValue(char i) | |
73 | { | |
74 | *this = JSValue(static_cast<int32_t>(i)); | |
75 | } | |
76 | ||
77 | inline JSValue::JSValue(unsigned char i) | |
78 | { | |
79 | *this = JSValue(static_cast<int32_t>(i)); | |
80 | } | |
81 | ||
82 | inline JSValue::JSValue(short i) | |
83 | { | |
84 | *this = JSValue(static_cast<int32_t>(i)); | |
85 | } | |
86 | ||
87 | inline JSValue::JSValue(unsigned short i) | |
88 | { | |
89 | *this = JSValue(static_cast<int32_t>(i)); | |
90 | } | |
91 | ||
92 | inline JSValue::JSValue(unsigned i) | |
93 | { | |
94 | if (static_cast<int32_t>(i) < 0) { | |
95 | *this = JSValue(EncodeAsDouble, static_cast<double>(i)); | |
96 | return; | |
97 | } | |
98 | *this = JSValue(static_cast<int32_t>(i)); | |
99 | } | |
100 | ||
101 | inline JSValue::JSValue(long i) | |
102 | { | |
103 | if (static_cast<int32_t>(i) != i) { | |
104 | *this = JSValue(EncodeAsDouble, static_cast<double>(i)); | |
105 | return; | |
106 | } | |
107 | *this = JSValue(static_cast<int32_t>(i)); | |
108 | } | |
109 | ||
110 | inline JSValue::JSValue(unsigned long i) | |
111 | { | |
112 | if (static_cast<uint32_t>(i) != i) { | |
113 | *this = JSValue(EncodeAsDouble, static_cast<double>(i)); | |
114 | return; | |
115 | } | |
116 | *this = JSValue(static_cast<uint32_t>(i)); | |
117 | } | |
118 | ||
119 | inline JSValue::JSValue(long long i) | |
120 | { | |
121 | if (static_cast<int32_t>(i) != i) { | |
122 | *this = JSValue(EncodeAsDouble, static_cast<double>(i)); | |
123 | return; | |
124 | } | |
125 | *this = JSValue(static_cast<int32_t>(i)); | |
126 | } | |
127 | ||
128 | inline JSValue::JSValue(unsigned long long i) | |
129 | { | |
130 | if (static_cast<uint32_t>(i) != i) { | |
131 | *this = JSValue(EncodeAsDouble, static_cast<double>(i)); | |
132 | return; | |
133 | } | |
134 | *this = JSValue(static_cast<uint32_t>(i)); | |
135 | } | |
136 | ||
137 | inline JSValue::JSValue(double d) | |
138 | { | |
139 | const int32_t asInt32 = static_cast<int32_t>(d); | |
140 | if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0 | |
141 | *this = JSValue(EncodeAsDouble, d); | |
142 | return; | |
143 | } | |
144 | *this = JSValue(static_cast<int32_t>(d)); | |
145 | } | |
146 | ||
147 | inline EncodedJSValue JSValue::encode(JSValue value) | |
148 | { | |
149 | return value.u.asInt64; | |
150 | } | |
151 | ||
152 | inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) | |
153 | { | |
154 | JSValue v; | |
155 | v.u.asInt64 = encodedJSValue; | |
156 | return v; | |
157 | } | |
158 | ||
159 | #if USE(JSVALUE32_64) | |
160 | inline JSValue::JSValue() | |
161 | { | |
162 | u.asBits.tag = EmptyValueTag; | |
163 | u.asBits.payload = 0; | |
164 | } | |
165 | ||
166 | inline JSValue::JSValue(JSNullTag) | |
167 | { | |
168 | u.asBits.tag = NullTag; | |
169 | u.asBits.payload = 0; | |
170 | } | |
171 | ||
172 | inline JSValue::JSValue(JSUndefinedTag) | |
173 | { | |
174 | u.asBits.tag = UndefinedTag; | |
175 | u.asBits.payload = 0; | |
176 | } | |
177 | ||
178 | inline JSValue::JSValue(JSTrueTag) | |
179 | { | |
180 | u.asBits.tag = BooleanTag; | |
181 | u.asBits.payload = 1; | |
182 | } | |
183 | ||
184 | inline JSValue::JSValue(JSFalseTag) | |
185 | { | |
186 | u.asBits.tag = BooleanTag; | |
187 | u.asBits.payload = 0; | |
188 | } | |
189 | ||
190 | inline JSValue::JSValue(HashTableDeletedValueTag) | |
191 | { | |
192 | u.asBits.tag = DeletedValueTag; | |
193 | u.asBits.payload = 0; | |
194 | } | |
195 | ||
196 | inline JSValue::JSValue(JSCell* ptr) | |
197 | { | |
198 | if (ptr) | |
199 | u.asBits.tag = CellTag; | |
200 | else | |
201 | u.asBits.tag = EmptyValueTag; | |
202 | u.asBits.payload = reinterpret_cast<int32_t>(ptr); | |
203 | } | |
204 | ||
205 | inline JSValue::JSValue(const JSCell* ptr) | |
206 | { | |
207 | if (ptr) | |
208 | u.asBits.tag = CellTag; | |
209 | else | |
210 | u.asBits.tag = EmptyValueTag; | |
211 | u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); | |
212 | } | |
213 | ||
81345200 | 214 | inline JSValue::operator UnspecifiedBoolType*() const |
93a37866 A |
215 | { |
216 | ASSERT(tag() != DeletedValueTag); | |
81345200 | 217 | return tag() != EmptyValueTag ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; |
93a37866 A |
218 | } |
219 | ||
220 | inline bool JSValue::operator==(const JSValue& other) const | |
221 | { | |
222 | return u.asInt64 == other.u.asInt64; | |
223 | } | |
224 | ||
225 | inline bool JSValue::operator!=(const JSValue& other) const | |
226 | { | |
227 | return u.asInt64 != other.u.asInt64; | |
228 | } | |
229 | ||
230 | inline bool JSValue::isEmpty() const | |
231 | { | |
232 | return tag() == EmptyValueTag; | |
233 | } | |
234 | ||
235 | inline bool JSValue::isUndefined() const | |
236 | { | |
237 | return tag() == UndefinedTag; | |
238 | } | |
239 | ||
240 | inline bool JSValue::isNull() const | |
241 | { | |
242 | return tag() == NullTag; | |
243 | } | |
244 | ||
245 | inline bool JSValue::isUndefinedOrNull() const | |
246 | { | |
247 | return isUndefined() || isNull(); | |
248 | } | |
249 | ||
250 | inline bool JSValue::isCell() const | |
251 | { | |
252 | return tag() == CellTag; | |
253 | } | |
254 | ||
255 | inline bool JSValue::isInt32() const | |
256 | { | |
257 | return tag() == Int32Tag; | |
258 | } | |
259 | ||
260 | inline bool JSValue::isDouble() const | |
261 | { | |
262 | return tag() < LowestTag; | |
263 | } | |
264 | ||
265 | inline bool JSValue::isTrue() const | |
266 | { | |
267 | return tag() == BooleanTag && payload(); | |
268 | } | |
269 | ||
270 | inline bool JSValue::isFalse() const | |
271 | { | |
272 | return tag() == BooleanTag && !payload(); | |
273 | } | |
274 | ||
275 | inline uint32_t JSValue::tag() const | |
276 | { | |
277 | return u.asBits.tag; | |
278 | } | |
279 | ||
280 | inline int32_t JSValue::payload() const | |
281 | { | |
282 | return u.asBits.payload; | |
283 | } | |
284 | ||
285 | inline int32_t JSValue::asInt32() const | |
286 | { | |
287 | ASSERT(isInt32()); | |
288 | return u.asBits.payload; | |
289 | } | |
290 | ||
291 | inline double JSValue::asDouble() const | |
292 | { | |
293 | ASSERT(isDouble()); | |
294 | return u.asDouble; | |
295 | } | |
296 | ||
297 | ALWAYS_INLINE JSCell* JSValue::asCell() const | |
298 | { | |
299 | ASSERT(isCell()); | |
300 | return reinterpret_cast<JSCell*>(u.asBits.payload); | |
301 | } | |
302 | ||
303 | ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) | |
304 | { | |
81345200 | 305 | ASSERT(!isImpureNaN(d)); |
93a37866 A |
306 | u.asDouble = d; |
307 | } | |
308 | ||
309 | inline JSValue::JSValue(int i) | |
310 | { | |
311 | u.asBits.tag = Int32Tag; | |
312 | u.asBits.payload = i; | |
313 | } | |
314 | ||
81345200 | 315 | #if !ENABLE(JIT) |
93a37866 A |
316 | inline JSValue::JSValue(int32_t tag, int32_t payload) |
317 | { | |
318 | u.asBits.tag = tag; | |
319 | u.asBits.payload = payload; | |
320 | } | |
321 | #endif | |
322 | ||
323 | inline bool JSValue::isNumber() const | |
324 | { | |
325 | return isInt32() || isDouble(); | |
326 | } | |
327 | ||
328 | inline bool JSValue::isBoolean() const | |
329 | { | |
330 | return isTrue() || isFalse(); | |
331 | } | |
332 | ||
333 | inline bool JSValue::asBoolean() const | |
334 | { | |
335 | ASSERT(isBoolean()); | |
336 | return payload(); | |
337 | } | |
338 | ||
339 | #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) | |
340 | ||
341 | // 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. | |
342 | inline JSValue::JSValue() | |
343 | { | |
344 | u.asInt64 = ValueEmpty; | |
345 | } | |
346 | ||
347 | // 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. | |
348 | inline JSValue::JSValue(HashTableDeletedValueTag) | |
349 | { | |
350 | u.asInt64 = ValueDeleted; | |
351 | } | |
352 | ||
353 | inline JSValue::JSValue(JSCell* ptr) | |
354 | { | |
355 | u.asInt64 = reinterpret_cast<uintptr_t>(ptr); | |
356 | } | |
357 | ||
358 | inline JSValue::JSValue(const JSCell* ptr) | |
359 | { | |
360 | u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr)); | |
361 | } | |
362 | ||
81345200 | 363 | inline JSValue::operator UnspecifiedBoolType*() const |
93a37866 | 364 | { |
81345200 | 365 | return u.asInt64 ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; |
93a37866 A |
366 | } |
367 | ||
368 | inline bool JSValue::operator==(const JSValue& other) const | |
369 | { | |
370 | return u.asInt64 == other.u.asInt64; | |
371 | } | |
372 | ||
373 | inline bool JSValue::operator!=(const JSValue& other) const | |
374 | { | |
375 | return u.asInt64 != other.u.asInt64; | |
376 | } | |
377 | ||
378 | inline bool JSValue::isEmpty() const | |
379 | { | |
380 | return u.asInt64 == ValueEmpty; | |
381 | } | |
382 | ||
383 | inline bool JSValue::isUndefined() const | |
384 | { | |
385 | return asValue() == JSValue(JSUndefined); | |
386 | } | |
387 | ||
388 | inline bool JSValue::isNull() const | |
389 | { | |
390 | return asValue() == JSValue(JSNull); | |
391 | } | |
392 | ||
393 | inline bool JSValue::isTrue() const | |
394 | { | |
395 | return asValue() == JSValue(JSTrue); | |
396 | } | |
397 | ||
398 | inline bool JSValue::isFalse() const | |
399 | { | |
400 | return asValue() == JSValue(JSFalse); | |
401 | } | |
402 | ||
403 | inline bool JSValue::asBoolean() const | |
404 | { | |
405 | ASSERT(isBoolean()); | |
406 | return asValue() == JSValue(JSTrue); | |
407 | } | |
408 | ||
409 | inline int32_t JSValue::asInt32() const | |
410 | { | |
411 | ASSERT(isInt32()); | |
412 | return static_cast<int32_t>(u.asInt64); | |
413 | } | |
414 | ||
415 | inline bool JSValue::isDouble() const | |
416 | { | |
417 | return isNumber() && !isInt32(); | |
418 | } | |
419 | ||
420 | inline JSValue::JSValue(JSNullTag) | |
421 | { | |
422 | u.asInt64 = ValueNull; | |
423 | } | |
424 | ||
425 | inline JSValue::JSValue(JSUndefinedTag) | |
426 | { | |
427 | u.asInt64 = ValueUndefined; | |
428 | } | |
429 | ||
430 | inline JSValue::JSValue(JSTrueTag) | |
431 | { | |
432 | u.asInt64 = ValueTrue; | |
433 | } | |
434 | ||
435 | inline JSValue::JSValue(JSFalseTag) | |
436 | { | |
437 | u.asInt64 = ValueFalse; | |
438 | } | |
439 | ||
440 | inline bool JSValue::isUndefinedOrNull() const | |
441 | { | |
442 | // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. | |
443 | return (u.asInt64 & ~TagBitUndefined) == ValueNull; | |
444 | } | |
445 | ||
446 | inline bool JSValue::isBoolean() const | |
447 | { | |
448 | return (u.asInt64 & ~1) == ValueFalse; | |
449 | } | |
450 | ||
451 | inline bool JSValue::isCell() const | |
452 | { | |
453 | return !(u.asInt64 & TagMask); | |
454 | } | |
455 | ||
456 | inline bool JSValue::isInt32() const | |
457 | { | |
458 | return (u.asInt64 & TagTypeNumber) == TagTypeNumber; | |
459 | } | |
460 | ||
461 | inline int64_t reinterpretDoubleToInt64(double value) | |
462 | { | |
463 | return bitwise_cast<int64_t>(value); | |
464 | } | |
465 | inline double reinterpretInt64ToDouble(int64_t value) | |
466 | { | |
467 | return bitwise_cast<double>(value); | |
468 | } | |
469 | ||
470 | ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) | |
471 | { | |
81345200 | 472 | ASSERT(!isImpureNaN(d)); |
93a37866 A |
473 | u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; |
474 | } | |
475 | ||
476 | inline JSValue::JSValue(int i) | |
477 | { | |
478 | u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i); | |
479 | } | |
480 | ||
481 | inline double JSValue::asDouble() const | |
482 | { | |
483 | ASSERT(isDouble()); | |
484 | return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset); | |
485 | } | |
486 | ||
487 | inline bool JSValue::isNumber() const | |
488 | { | |
489 | return u.asInt64 & TagTypeNumber; | |
490 | } | |
491 | ||
492 | ALWAYS_INLINE JSCell* JSValue::asCell() const | |
493 | { | |
494 | ASSERT(isCell()); | |
495 | return u.ptr; | |
496 | } | |
497 | ||
498 | #endif // USE(JSVALUE64) | |
499 | ||
81345200 A |
500 | inline int64_t tryConvertToInt52(double number) |
501 | { | |
502 | if (number != number) | |
503 | return JSValue::notInt52; | |
504 | #if OS(WINDOWS) && CPU(X86) | |
505 | // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast | |
506 | // from an infinity to a 64-bit integer. We leave this routine with the floating point error | |
507 | // left in a register, causing undefined behavior in later floating point operations. | |
508 | // | |
509 | // To avoid this issue, we check for infinity here, and return false in that case. | |
510 | if (std::isinf(number)) | |
511 | return JSValue::notInt52; | |
512 | #endif | |
513 | int64_t asInt64 = static_cast<int64_t>(number); | |
514 | if (asInt64 != number) | |
515 | return JSValue::notInt52; | |
516 | if (!asInt64 && std::signbit(number)) | |
517 | return JSValue::notInt52; | |
518 | if (asInt64 >= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1))) | |
519 | return JSValue::notInt52; | |
520 | if (asInt64 < -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1))) | |
521 | return JSValue::notInt52; | |
522 | return asInt64; | |
523 | } | |
524 | ||
525 | inline bool isInt52(double number) | |
526 | { | |
527 | return tryConvertToInt52(number) != JSValue::notInt52; | |
528 | } | |
529 | ||
530 | inline bool JSValue::isMachineInt() const | |
531 | { | |
532 | if (isInt32()) | |
533 | return true; | |
534 | if (!isNumber()) | |
535 | return false; | |
536 | return isInt52(asDouble()); | |
537 | } | |
538 | ||
539 | inline int64_t JSValue::asMachineInt() const | |
540 | { | |
541 | ASSERT(isMachineInt()); | |
542 | if (isInt32()) | |
543 | return asInt32(); | |
544 | return static_cast<int64_t>(asDouble()); | |
545 | } | |
546 | ||
93a37866 A |
547 | inline bool JSValue::isString() const |
548 | { | |
549 | return isCell() && asCell()->isString(); | |
550 | } | |
551 | ||
552 | inline bool JSValue::isPrimitive() const | |
553 | { | |
554 | return !isCell() || asCell()->isString(); | |
555 | } | |
556 | ||
557 | inline bool JSValue::isGetterSetter() const | |
558 | { | |
559 | return isCell() && asCell()->isGetterSetter(); | |
560 | } | |
561 | ||
81345200 A |
562 | inline bool JSValue::isCustomGetterSetter() const |
563 | { | |
564 | return isCell() && asCell()->isCustomGetterSetter(); | |
565 | } | |
566 | ||
93a37866 A |
567 | inline bool JSValue::isObject() const |
568 | { | |
569 | return isCell() && asCell()->isObject(); | |
570 | } | |
571 | ||
572 | inline bool JSValue::getString(ExecState* exec, String& s) const | |
573 | { | |
574 | return isCell() && asCell()->getString(exec, s); | |
575 | } | |
576 | ||
577 | inline String JSValue::getString(ExecState* exec) const | |
578 | { | |
579 | return isCell() ? asCell()->getString(exec) : String(); | |
580 | } | |
581 | ||
582 | template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const | |
583 | { | |
584 | return jsValue().getString(exec); | |
585 | } | |
586 | ||
587 | inline JSObject* JSValue::getObject() const | |
588 | { | |
589 | return isCell() ? asCell()->getObject() : 0; | |
590 | } | |
591 | ||
592 | ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const | |
593 | { | |
594 | if (isInt32()) { | |
595 | int32_t i = asInt32(); | |
596 | v = static_cast<uint32_t>(i); | |
597 | return i >= 0; | |
598 | } | |
599 | if (isDouble()) { | |
600 | double d = asDouble(); | |
601 | v = static_cast<uint32_t>(d); | |
602 | return v == d; | |
603 | } | |
604 | return false; | |
605 | } | |
606 | ||
607 | inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const | |
608 | { | |
609 | return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); | |
610 | } | |
611 | ||
612 | inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) | |
613 | { | |
614 | if (isInt32()) { | |
615 | number = asInt32(); | |
616 | value = *this; | |
617 | return true; | |
618 | } | |
619 | if (isDouble()) { | |
620 | number = asDouble(); | |
621 | value = *this; | |
622 | return true; | |
623 | } | |
624 | if (isCell()) | |
625 | return asCell()->getPrimitiveNumber(exec, number, value); | |
626 | if (isTrue()) { | |
627 | number = 1.0; | |
628 | value = *this; | |
629 | return true; | |
630 | } | |
631 | if (isFalse() || isNull()) { | |
632 | number = 0.0; | |
633 | value = *this; | |
634 | return true; | |
635 | } | |
636 | ASSERT(isUndefined()); | |
81345200 | 637 | number = PNaN; |
93a37866 A |
638 | value = *this; |
639 | return true; | |
640 | } | |
641 | ||
642 | ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const | |
643 | { | |
644 | if (isInt32()) | |
645 | return asInt32(); | |
646 | if (isDouble()) | |
647 | return asDouble(); | |
648 | return toNumberSlowCase(exec); | |
649 | } | |
650 | ||
651 | inline JSObject* JSValue::toObject(ExecState* exec) const | |
652 | { | |
653 | return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); | |
654 | } | |
655 | ||
656 | inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const | |
657 | { | |
658 | return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); | |
659 | } | |
660 | ||
661 | inline bool JSValue::isFunction() const | |
662 | { | |
81345200 | 663 | return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info())); |
93a37866 A |
664 | } |
665 | ||
666 | // this method is here to be after the inline declaration of JSCell::inherits | |
667 | inline bool JSValue::inherits(const ClassInfo* classInfo) const | |
668 | { | |
669 | return isCell() && asCell()->inherits(classInfo); | |
670 | } | |
671 | ||
81345200 | 672 | inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const |
93a37866 | 673 | { |
81345200 | 674 | return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode); |
93a37866 A |
675 | } |
676 | ||
81345200 | 677 | ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const |
93a37866 A |
678 | { |
679 | PropertySlot slot(asValue()); | |
680 | return get(exec, propertyName, slot); | |
681 | } | |
682 | ||
81345200 | 683 | ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const |
93a37866 | 684 | { |
81345200 A |
685 | // If this is a primitive, we'll need to synthesize the prototype - |
686 | // and if it's a string there are special properties to check first. | |
687 | JSObject* object; | |
688 | if (UNLIKELY(!isObject())) { | |
689 | if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot)) | |
93a37866 | 690 | return slot.getValue(exec, propertyName); |
81345200 A |
691 | object = synthesizePrototype(exec); |
692 | } else | |
693 | object = asObject(asCell()); | |
694 | ||
695 | if (object->getPropertySlot(exec, propertyName, slot)) | |
696 | return slot.getValue(exec, propertyName); | |
697 | return jsUndefined(); | |
93a37866 A |
698 | } |
699 | ||
81345200 | 700 | ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const |
93a37866 A |
701 | { |
702 | PropertySlot slot(asValue()); | |
703 | return get(exec, propertyName, slot); | |
704 | } | |
705 | ||
81345200 | 706 | ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const |
93a37866 | 707 | { |
81345200 A |
708 | // If this is a primitive, we'll need to synthesize the prototype - |
709 | // and if it's a string there are special properties to check first. | |
710 | JSObject* object; | |
711 | if (UNLIKELY(!isObject())) { | |
712 | if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot)) | |
93a37866 | 713 | return slot.getValue(exec, propertyName); |
81345200 A |
714 | object = synthesizePrototype(exec); |
715 | } else | |
716 | object = asObject(asCell()); | |
717 | ||
718 | if (object->getPropertySlot(exec, propertyName, slot)) | |
719 | return slot.getValue(exec, propertyName); | |
720 | return jsUndefined(); | |
93a37866 A |
721 | } |
722 | ||
723 | inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) | |
724 | { | |
725 | if (UNLIKELY(!isCell())) { | |
726 | putToPrimitive(exec, propertyName, value, slot); | |
727 | return; | |
728 | } | |
81345200 | 729 | asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot); |
93a37866 A |
730 | } |
731 | ||
732 | inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) | |
733 | { | |
734 | if (UNLIKELY(!isCell())) { | |
735 | putToPrimitiveByIndex(exec, propertyName, value, shouldThrow); | |
736 | return; | |
737 | } | |
81345200 | 738 | asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow); |
93a37866 A |
739 | } |
740 | ||
741 | inline JSValue JSValue::structureOrUndefined() const | |
742 | { | |
743 | if (isCell()) | |
744 | return JSValue(asCell()->structure()); | |
745 | return jsUndefined(); | |
746 | } | |
747 | ||
748 | // ECMA 11.9.3 | |
749 | inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) | |
750 | { | |
751 | if (v1.isInt32() && v2.isInt32()) | |
752 | return v1 == v2; | |
753 | ||
754 | return equalSlowCase(exec, v1, v2); | |
755 | } | |
756 | ||
757 | ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) | |
758 | { | |
81345200 | 759 | VM& vm = exec->vm(); |
93a37866 A |
760 | do { |
761 | if (v1.isNumber() && v2.isNumber()) | |
762 | return v1.asNumber() == v2.asNumber(); | |
763 | ||
764 | bool s1 = v1.isString(); | |
765 | bool s2 = v2.isString(); | |
766 | if (s1 && s2) | |
81345200 | 767 | return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl()); |
93a37866 A |
768 | |
769 | if (v1.isUndefinedOrNull()) { | |
770 | if (v2.isUndefinedOrNull()) | |
771 | return true; | |
772 | if (!v2.isCell()) | |
773 | return false; | |
81345200 | 774 | return v2.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject()); |
93a37866 A |
775 | } |
776 | ||
777 | if (v2.isUndefinedOrNull()) { | |
778 | if (!v1.isCell()) | |
779 | return false; | |
81345200 | 780 | return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject()); |
93a37866 A |
781 | } |
782 | ||
783 | if (v1.isObject()) { | |
784 | if (v2.isObject()) | |
785 | return v1 == v2; | |
786 | JSValue p1 = v1.toPrimitive(exec); | |
787 | if (exec->hadException()) | |
788 | return false; | |
789 | v1 = p1; | |
790 | if (v1.isInt32() && v2.isInt32()) | |
791 | return v1 == v2; | |
792 | continue; | |
793 | } | |
794 | ||
795 | if (v2.isObject()) { | |
796 | JSValue p2 = v2.toPrimitive(exec); | |
797 | if (exec->hadException()) | |
798 | return false; | |
799 | v2 = p2; | |
800 | if (v1.isInt32() && v2.isInt32()) | |
801 | return v1 == v2; | |
802 | continue; | |
803 | } | |
804 | ||
805 | if (s1 || s2) { | |
806 | double d1 = v1.toNumber(exec); | |
807 | double d2 = v2.toNumber(exec); | |
808 | return d1 == d2; | |
809 | } | |
810 | ||
811 | if (v1.isBoolean()) { | |
812 | if (v2.isNumber()) | |
813 | return static_cast<double>(v1.asBoolean()) == v2.asNumber(); | |
814 | } else if (v2.isBoolean()) { | |
815 | if (v1.isNumber()) | |
816 | return v1.asNumber() == static_cast<double>(v2.asBoolean()); | |
817 | } | |
818 | ||
819 | return v1 == v2; | |
820 | } while (true); | |
821 | } | |
822 | ||
823 | // ECMA 11.9.3 | |
824 | ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) | |
825 | { | |
826 | ASSERT(v1.isCell() && v2.isCell()); | |
827 | ||
828 | if (v1.asCell()->isString() && v2.asCell()->isString()) | |
81345200 | 829 | return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl()); |
93a37866 A |
830 | |
831 | return v1 == v2; | |
832 | } | |
833 | ||
834 | inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2) | |
835 | { | |
836 | if (v1.isInt32() && v2.isInt32()) | |
837 | return v1 == v2; | |
838 | ||
839 | if (v1.isNumber() && v2.isNumber()) | |
840 | return v1.asNumber() == v2.asNumber(); | |
841 | ||
842 | if (!v1.isCell() || !v2.isCell()) | |
843 | return v1 == v2; | |
844 | ||
845 | return strictEqualSlowCaseInline(exec, v1, v2); | |
846 | } | |
847 | ||
81345200 A |
848 | inline int32_t JSValue::asInt32ForArithmetic() const |
849 | { | |
850 | if (isBoolean()) | |
851 | return asBoolean(); | |
852 | return asInt32(); | |
853 | } | |
854 | ||
855 | inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2) | |
856 | { | |
857 | if (v1.isInt32() && v2.isInt32()) | |
858 | return triState(v1 == v2); | |
859 | ||
860 | if (v1.isNumber() && v2.isNumber()) | |
861 | return triState(v1.asNumber() == v2.asNumber()); | |
862 | ||
863 | if (!v1.isCell() || !v2.isCell()) | |
864 | return triState(v1 == v2); | |
865 | ||
866 | if (v1.asCell()->isString() && v2.asCell()->isString()) { | |
867 | const StringImpl* v1String = asString(v1)->tryGetValueImpl(); | |
868 | const StringImpl* v2String = asString(v2)->tryGetValueImpl(); | |
869 | if (!v1String || !v2String) | |
870 | return MixedTriState; | |
871 | return triState(WTF::equal(*v1String, *v2String)); | |
872 | } | |
873 | ||
874 | return triState(v1 == v2); | |
875 | } | |
876 | ||
93a37866 A |
877 | inline TriState JSValue::pureToBoolean() const |
878 | { | |
879 | if (isInt32()) | |
880 | return asInt32() ? TrueTriState : FalseTriState; | |
881 | if (isDouble()) | |
882 | return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN | |
883 | if (isCell()) | |
884 | return asCell()->pureToBoolean(); | |
885 | return isTrue() ? TrueTriState : FalseTriState; | |
886 | } | |
887 | ||
888 | } // namespace JSC | |
889 | ||
890 | #endif // JSValueInlines_h | |
891 |