2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6 * Copyright (C) 2007 Maks Orlovich
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "JSGlobalObjectFunctions.h"
28 #include "CallFrame.h"
29 #include "Interpreter.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
33 #include "JSStringBuilder.h"
35 #include "LiteralParser.h"
37 #include "JSCInlines.h"
39 #include "StackVisitor.h"
43 #include <wtf/ASCIICType.h>
44 #include <wtf/Assertions.h>
45 #include <wtf/MathExtras.h>
46 #include <wtf/StringExtras.h>
47 #include <wtf/text/StringBuilder.h>
48 #include <wtf/unicode/UTF8.h>
51 using namespace Unicode
;
55 static JSValue
encode(ExecState
* exec
, const char* doNotEscape
)
57 CString cstr
= exec
->argument(0).toString(exec
)->value(exec
).utf8(StrictConversion
);
59 return exec
->vm().throwException(exec
, createURIError(exec
, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
61 JSStringBuilder builder
;
62 const char* p
= cstr
.data();
63 for (size_t k
= 0; k
< cstr
.length(); k
++, p
++) {
65 if (c
&& strchr(doNotEscape
, c
))
66 builder
.append(static_cast<LChar
>(c
));
69 snprintf(tmp
, sizeof(tmp
), "%%%02X", static_cast<unsigned char>(c
));
73 return builder
.build(exec
);
76 template <typename CharType
>
78 static JSValue
decode(ExecState
* exec
, const CharType
* characters
, int length
, const char* doNotUnescape
, bool strict
)
80 JSStringBuilder builder
;
84 const CharType
* p
= characters
+ k
;
88 if (k
<= length
- 3 && isASCIIHexDigit(p
[1]) && isASCIIHexDigit(p
[2])) {
89 const char b0
= Lexer
<CharType
>::convertHex(p
[1], p
[2]);
90 const int sequenceLen
= UTF8SequenceLength(b0
);
91 if (sequenceLen
&& k
<= length
- sequenceLen
* 3) {
92 charLen
= sequenceLen
* 3;
95 for (int i
= 1; i
< sequenceLen
; ++i
) {
96 const CharType
* q
= p
+ i
* 3;
97 if (q
[0] == '%' && isASCIIHexDigit(q
[1]) && isASCIIHexDigit(q
[2]))
98 sequence
[i
] = Lexer
<CharType
>::convertHex(q
[1], q
[2]);
105 sequence
[sequenceLen
] = 0;
106 const int character
= decodeUTF8Sequence(sequence
);
107 if (character
< 0 || character
>= 0x110000)
109 else if (character
>= 0x10000) {
110 // Convert to surrogate pair.
111 builder
.append(static_cast<UChar
>(0xD800 | ((character
- 0x10000) >> 10)));
112 u
= static_cast<UChar
>(0xDC00 | ((character
- 0x10000) & 0x3FF));
114 u
= static_cast<UChar
>(character
);
120 return exec
->vm().throwException(exec
, createURIError(exec
, ASCIILiteral("URI error")));
121 // The only case where we don't use "strict" mode is the "unescape" function.
122 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
123 if (k
<= length
- 6 && p
[1] == 'u'
124 && isASCIIHexDigit(p
[2]) && isASCIIHexDigit(p
[3])
125 && isASCIIHexDigit(p
[4]) && isASCIIHexDigit(p
[5])) {
127 u
= Lexer
<UChar
>::convertUnicode(p
[2], p
[3], p
[4], p
[5]);
130 if (charLen
&& (u
== 0 || u
>= 128 || !strchr(doNotUnescape
, u
))) {
139 return builder
.build(exec
);
142 static JSValue
decode(ExecState
* exec
, const char* doNotUnescape
, bool strict
)
144 String str
= exec
->argument(0).toString(exec
)->value(exec
);
147 return decode(exec
, str
.characters8(), str
.length(), doNotUnescape
, strict
);
148 return decode(exec
, str
.characters16(), str
.length(), doNotUnescape
, strict
);
151 bool isStrWhiteSpace(UChar c
)
154 // ECMA-262-5th 7.2 & 7.3
162 case 0x180E: // This character used to be in Zs category before Unicode 6.3, and EcmaScript says that we should keep treating it as such.
168 return c
> 0xFF && u_charType(c
) == U_SPACE_SEPARATOR
;
172 static int parseDigit(unsigned short c
, int radix
)
176 if (c
>= '0' && c
<= '9')
178 else if (c
>= 'A' && c
<= 'Z')
179 digit
= c
- 'A' + 10;
180 else if (c
>= 'a' && c
<= 'z')
181 digit
= c
- 'a' + 10;
188 double parseIntOverflow(const LChar
* s
, unsigned length
, int radix
)
191 double radixMultiplier
= 1.0;
193 for (const LChar
* p
= s
+ length
- 1; p
>= s
; p
--) {
194 if (radixMultiplier
== std::numeric_limits
<double>::infinity()) {
196 number
= std::numeric_limits
<double>::infinity();
200 int digit
= parseDigit(*p
, radix
);
201 number
+= digit
* radixMultiplier
;
204 radixMultiplier
*= radix
;
210 static double parseIntOverflow(const UChar
* s
, unsigned length
, int radix
)
213 double radixMultiplier
= 1.0;
215 for (const UChar
* p
= s
+ length
- 1; p
>= s
; p
--) {
216 if (radixMultiplier
== std::numeric_limits
<double>::infinity()) {
218 number
= std::numeric_limits
<double>::infinity();
222 int digit
= parseDigit(*p
, radix
);
223 number
+= digit
* radixMultiplier
;
226 radixMultiplier
*= radix
;
232 static double parseIntOverflow(StringView string
, int radix
)
235 return parseIntOverflow(string
.characters8(), string
.length(), radix
);
236 return parseIntOverflow(string
.characters16(), string
.length(), radix
);
240 template <typename CharType
>
242 static double parseInt(const String
& s
, const CharType
* data
, int radix
)
244 // 1. Let inputString be ToString(string).
245 // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
246 // StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
247 // space.) If inputString does not contain any such characters, let S be the empty string.
248 int length
= s
.length();
250 while (p
< length
&& isStrWhiteSpace(data
[p
]))
254 // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
255 // 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S.
260 else if (data
[p
] == '-') {
266 // 6. Let R = ToInt32(radix).
267 // 7. Let stripPrefix be true.
269 // b. If R != 16, let stripPrefix be false.
272 // 10. If stripPrefix is true, then
273 // a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
274 // then remove the first two characters from S and let R = 16.
275 // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
276 // consisting of all characters before the first such character; otherwise, let Z be S.
277 if ((radix
== 0 || radix
== 16) && length
- p
>= 2 && data
[p
] == '0' && (data
[p
+ 1] == 'x' || data
[p
+ 1] == 'X')) {
280 } else if (radix
== 0)
283 // 8.a If R < 2 or R > 36, then return NaN.
284 if (radix
< 2 || radix
> 36)
287 // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
288 // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
289 // digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
290 // and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
291 // mathematical integer value that is represented by Z in radix-R notation.)
292 // 14. Let number be the Number value for mathInt.
293 int firstDigitPosition
= p
;
294 bool sawDigit
= false;
297 int digit
= parseDigit(data
[p
], radix
);
306 // 12. If Z is empty, return NaN.
310 // Alternate code path for certain large numbers.
311 if (number
>= mantissaOverflowLowerBound
) {
314 number
= parseDouble(StringView(s
).substring(firstDigitPosition
, p
- firstDigitPosition
), parsedLength
);
315 } else if (radix
== 2 || radix
== 4 || radix
== 8 || radix
== 16 || radix
== 32)
316 number
= parseIntOverflow(StringView(s
).substring(firstDigitPosition
, p
- firstDigitPosition
), radix
);
319 // 15. Return sign x number.
320 return sign
* number
;
323 static double parseInt(const String
& s
, int radix
)
326 return parseInt(s
, s
.characters8(), radix
);
327 return parseInt(s
, s
.characters16(), radix
);
330 static const int SizeOfInfinity
= 8;
332 template <typename CharType
>
333 static bool isInfinity(const CharType
* data
, const CharType
* end
)
335 return (end
- data
) >= SizeOfInfinity
346 // See ecma-262 9.3.1
347 template <typename CharType
>
348 static double jsHexIntegerLiteral(const CharType
*& data
, const CharType
* end
)
352 const CharType
* firstDigitPosition
= data
;
355 number
= number
* 16 + toASCIIHexValue(*data
);
359 if (!isASCIIHexDigit(*data
))
362 if (number
>= mantissaOverflowLowerBound
)
363 number
= parseIntOverflow(firstDigitPosition
, data
- firstDigitPosition
, 16);
368 // See ecma-262 9.3.1
369 template <typename CharType
>
370 static double jsStrDecimalLiteral(const CharType
*& data
, const CharType
* end
)
372 RELEASE_ASSERT(data
< end
);
375 double number
= parseDouble(data
, end
- data
, parsedLength
);
377 data
+= parsedLength
;
381 // Check for [+-]?Infinity
384 if (isInfinity(data
, end
)) {
385 data
+= SizeOfInfinity
;
386 return std::numeric_limits
<double>::infinity();
391 if (isInfinity(data
+ 1, end
)) {
392 data
+= SizeOfInfinity
+ 1;
393 return std::numeric_limits
<double>::infinity();
398 if (isInfinity(data
+ 1, end
)) {
399 data
+= SizeOfInfinity
+ 1;
400 return -std::numeric_limits
<double>::infinity();
409 template <typename CharType
>
410 static double toDouble(const CharType
* characters
, unsigned size
)
412 const CharType
* endCharacters
= characters
+ size
;
414 // Skip leading white space.
415 for (; characters
< endCharacters
; ++characters
) {
416 if (!isStrWhiteSpace(*characters
))
421 if (characters
== endCharacters
)
425 if (characters
[0] == '0' && characters
+ 2 < endCharacters
&& (characters
[1] | 0x20) == 'x' && isASCIIHexDigit(characters
[2]))
426 number
= jsHexIntegerLiteral(characters
, endCharacters
);
428 number
= jsStrDecimalLiteral(characters
, endCharacters
);
430 // Allow trailing white space.
431 for (; characters
< endCharacters
; ++characters
) {
432 if (!isStrWhiteSpace(*characters
))
435 if (characters
!= endCharacters
)
441 // See ecma-262 9.3.1
442 double jsToNumber(const String
& s
)
444 unsigned size
= s
.length();
450 if (isStrWhiteSpace(c
))
456 return toDouble(s
.characters8(), size
);
457 return toDouble(s
.characters16(), size
);
460 static double parseFloat(const String
& s
)
462 unsigned size
= s
.length();
472 const LChar
* data
= s
.characters8();
473 const LChar
* end
= data
+ size
;
475 // Skip leading white space.
476 for (; data
< end
; ++data
) {
477 if (!isStrWhiteSpace(*data
))
485 return jsStrDecimalLiteral(data
, end
);
488 const UChar
* data
= s
.characters16();
489 const UChar
* end
= data
+ size
;
491 // Skip leading white space.
492 for (; data
< end
; ++data
) {
493 if (!isStrWhiteSpace(*data
))
501 return jsStrDecimalLiteral(data
, end
);
504 EncodedJSValue JSC_HOST_CALL
globalFuncEval(ExecState
* exec
)
506 JSValue x
= exec
->argument(0);
508 return JSValue::encode(x
);
510 String s
= x
.toString(exec
)->value(exec
);
513 LiteralParser
<LChar
> preparser(exec
, s
.characters8(), s
.length(), NonStrictJSON
);
514 if (JSValue parsedObject
= preparser
.tryLiteralParse())
515 return JSValue::encode(parsedObject
);
517 LiteralParser
<UChar
> preparser(exec
, s
.characters16(), s
.length(), NonStrictJSON
);
518 if (JSValue parsedObject
= preparser
.tryLiteralParse())
519 return JSValue::encode(parsedObject
);
522 JSGlobalObject
* calleeGlobalObject
= exec
->callee()->globalObject();
523 EvalExecutable
* eval
= EvalExecutable::create(exec
, makeSource(s
), false);
525 return JSValue::encode(jsUndefined());
527 return JSValue::encode(exec
->interpreter()->execute(eval
, exec
, calleeGlobalObject
->globalThis(), calleeGlobalObject
));
530 EncodedJSValue JSC_HOST_CALL
globalFuncParseInt(ExecState
* exec
)
532 JSValue value
= exec
->argument(0);
533 JSValue radixValue
= exec
->argument(1);
535 // Optimized handling for numbers:
536 // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
537 // results in a truncation to integer. In the case of -0, this is converted to 0.
539 // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
540 // however these values cannot be trivially truncated to int since 10^21 exceeds
541 // even the int64_t range. Negative numbers are a little trickier, the case for
542 // values in the range -10^21 < n <= -1 are similar to those for integer, but
543 // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
544 static const double tenToTheMinus6
= 0.000001;
545 static const double intMaxPlusOne
= 2147483648.0;
546 if (value
.isNumber()) {
547 double n
= value
.asNumber();
548 if (((n
< intMaxPlusOne
&& n
>= tenToTheMinus6
) || !n
) && radixValue
.isUndefinedOrNull())
549 return JSValue::encode(jsNumber(static_cast<int32_t>(n
)));
552 // If ToString throws, we shouldn't call ToInt32.
553 String s
= value
.toString(exec
)->value(exec
);
554 if (exec
->hadException())
555 return JSValue::encode(jsUndefined());
557 return JSValue::encode(jsNumber(parseInt(s
, radixValue
.toInt32(exec
))));
560 EncodedJSValue JSC_HOST_CALL
globalFuncParseFloat(ExecState
* exec
)
562 return JSValue::encode(jsNumber(parseFloat(exec
->argument(0).toString(exec
)->value(exec
))));
565 EncodedJSValue JSC_HOST_CALL
globalFuncIsNaN(ExecState
* exec
)
567 return JSValue::encode(jsBoolean(std::isnan(exec
->argument(0).toNumber(exec
))));
570 EncodedJSValue JSC_HOST_CALL
globalFuncIsFinite(ExecState
* exec
)
572 double n
= exec
->argument(0).toNumber(exec
);
573 return JSValue::encode(jsBoolean(std::isfinite(n
)));
576 EncodedJSValue JSC_HOST_CALL
globalFuncDecodeURI(ExecState
* exec
)
578 static const char do_not_unescape_when_decoding_URI
[] =
581 return JSValue::encode(decode(exec
, do_not_unescape_when_decoding_URI
, true));
584 EncodedJSValue JSC_HOST_CALL
globalFuncDecodeURIComponent(ExecState
* exec
)
586 return JSValue::encode(decode(exec
, "", true));
589 EncodedJSValue JSC_HOST_CALL
globalFuncEncodeURI(ExecState
* exec
)
591 static const char do_not_escape_when_encoding_URI
[] =
592 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
593 "abcdefghijklmnopqrstuvwxyz"
595 "!#$&'()*+,-./:;=?@_~";
597 return JSValue::encode(encode(exec
, do_not_escape_when_encoding_URI
));
600 EncodedJSValue JSC_HOST_CALL
globalFuncEncodeURIComponent(ExecState
* exec
)
602 static const char do_not_escape_when_encoding_URI_component
[] =
603 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
604 "abcdefghijklmnopqrstuvwxyz"
608 return JSValue::encode(encode(exec
, do_not_escape_when_encoding_URI_component
));
611 EncodedJSValue JSC_HOST_CALL
globalFuncEscape(ExecState
* exec
)
613 static const char do_not_escape
[] =
614 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
615 "abcdefghijklmnopqrstuvwxyz"
619 JSStringBuilder builder
;
620 String str
= exec
->argument(0).toString(exec
)->value(exec
);
622 const LChar
* c
= str
.characters8();
623 for (unsigned k
= 0; k
< str
.length(); k
++, c
++) {
625 if (u
&& strchr(do_not_escape
, static_cast<char>(u
)))
629 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
634 return JSValue::encode(builder
.build(exec
));
637 const UChar
* c
= str
.characters16();
638 for (unsigned k
= 0; k
< str
.length(); k
++, c
++) {
642 snprintf(tmp
, sizeof(tmp
), "%%u%04X", u
);
644 } else if (u
!= 0 && strchr(do_not_escape
, static_cast<char>(u
)))
648 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
653 return JSValue::encode(builder
.build(exec
));
656 EncodedJSValue JSC_HOST_CALL
globalFuncUnescape(ExecState
* exec
)
658 StringBuilder builder
;
659 String str
= exec
->argument(0).toString(exec
)->value(exec
);
661 int len
= str
.length();
664 const LChar
* characters
= str
.characters8();
665 LChar convertedLChar
;
667 const LChar
* c
= characters
+ k
;
668 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
669 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
670 builder
.append(Lexer
<UChar
>::convertUnicode(c
[2], c
[3], c
[4], c
[5]));
674 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
675 convertedLChar
= LChar(Lexer
<LChar
>::convertHex(c
[1], c
[2]));
683 const UChar
* characters
= str
.characters16();
686 const UChar
* c
= characters
+ k
;
687 UChar convertedUChar
;
688 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
689 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
690 convertedUChar
= Lexer
<UChar
>::convertUnicode(c
[2], c
[3], c
[4], c
[5]);
694 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
695 convertedUChar
= UChar(Lexer
<UChar
>::convertHex(c
[1], c
[2]));
704 return JSValue::encode(jsString(exec
, builder
.toString()));
707 EncodedJSValue JSC_HOST_CALL
globalFuncThrowTypeError(ExecState
* exec
)
709 return throwVMTypeError(exec
);
712 class GlobalFuncProtoGetterFunctor
{
714 GlobalFuncProtoGetterFunctor(JSObject
* thisObject
)
715 : m_hasSkippedFirstFrame(false)
716 , m_thisObject(thisObject
)
717 , m_result(JSValue::encode(jsUndefined()))
721 EncodedJSValue
result() { return m_result
; }
723 StackVisitor::Status
operator()(StackVisitor
& visitor
)
725 if (!m_hasSkippedFirstFrame
) {
726 m_hasSkippedFirstFrame
= true;
727 return StackVisitor::Continue
;
730 if (m_thisObject
->allowsAccessFrom(visitor
->callFrame()))
731 m_result
= JSValue::encode(m_thisObject
->prototype());
733 return StackVisitor::Done
;
737 bool m_hasSkippedFirstFrame
;
738 JSObject
* m_thisObject
;
739 EncodedJSValue m_result
;
742 EncodedJSValue JSC_HOST_CALL
globalFuncProtoGetter(ExecState
* exec
)
744 JSObject
* thisObject
= jsDynamicCast
<JSObject
*>(exec
->thisValue().toThis(exec
, NotStrictMode
));
747 return JSValue::encode(exec
->thisValue().synthesizePrototype(exec
));
749 GlobalFuncProtoGetterFunctor
functor(thisObject
);
750 exec
->iterate(functor
);
751 return functor
.result();
754 class GlobalFuncProtoSetterFunctor
{
756 GlobalFuncProtoSetterFunctor(JSObject
* thisObject
)
757 : m_hasSkippedFirstFrame(false)
758 , m_allowsAccess(false)
759 , m_thisObject(thisObject
)
763 bool allowsAccess() const { return m_allowsAccess
; }
765 StackVisitor::Status
operator()(StackVisitor
& visitor
)
767 if (!m_hasSkippedFirstFrame
) {
768 m_hasSkippedFirstFrame
= true;
769 return StackVisitor::Continue
;
772 m_allowsAccess
= m_thisObject
->allowsAccessFrom(visitor
->callFrame());
773 return StackVisitor::Done
;
777 bool m_hasSkippedFirstFrame
;
779 JSObject
* m_thisObject
;
782 EncodedJSValue JSC_HOST_CALL
globalFuncProtoSetter(ExecState
* exec
)
784 JSValue value
= exec
->argument(0);
786 JSObject
* thisObject
= jsDynamicCast
<JSObject
*>(exec
->thisValue().toThis(exec
, NotStrictMode
));
788 // Setting __proto__ of a primitive should have no effect.
790 return JSValue::encode(jsUndefined());
792 GlobalFuncProtoSetterFunctor
functor(thisObject
);
793 exec
->iterate(functor
);
794 if (!functor
.allowsAccess())
795 return JSValue::encode(jsUndefined());
797 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
798 if (!value
.isObject() && !value
.isNull())
799 return JSValue::encode(jsUndefined());
801 if (!thisObject
->isExtensible())
802 return throwVMError(exec
, createTypeError(exec
, StrictModeReadonlyPropertyWriteError
));
804 if (!thisObject
->setPrototypeWithCycleCheck(exec
, value
))
805 exec
->vm().throwException(exec
, createError(exec
, "cyclic __proto__ value"));
806 return JSValue::encode(jsUndefined());
809 EncodedJSValue JSC_HOST_CALL
globalFuncBuiltinLog(ExecState
* exec
)
811 dataLog(exec
->argument(0).toWTFString(exec
), "\n");
812 return JSValue::encode(jsUndefined());