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 "JSGlobalObject.h"
32 #include "JSStringBuilder.h"
34 #include "LiteralParser.h"
37 #include "UStringBuilder.h"
41 #include <wtf/ASCIICType.h>
42 #include <wtf/Assertions.h>
43 #include <wtf/MathExtras.h>
44 #include <wtf/StringExtras.h>
45 #include <wtf/unicode/UTF8.h>
48 using namespace Unicode
;
52 static JSValue
encode(ExecState
* exec
, const char* doNotEscape
)
54 CString cstr
= exec
->argument(0).toString(exec
)->value(exec
).utf8(true);
56 return throwError(exec
, createURIError(exec
, "String contained an illegal UTF-16 sequence."));
58 JSStringBuilder builder
;
59 const char* p
= cstr
.data();
60 for (size_t k
= 0; k
< cstr
.length(); k
++, p
++) {
62 if (c
&& strchr(doNotEscape
, c
))
66 snprintf(tmp
, sizeof(tmp
), "%%%02X", static_cast<unsigned char>(c
));
70 return builder
.build(exec
);
73 template <typename CharType
>
75 static JSValue
decode(ExecState
* exec
, const CharType
* characters
, int length
, const char* doNotUnescape
, bool strict
)
77 JSStringBuilder builder
;
81 const CharType
* p
= characters
+ k
;
85 if (k
<= length
- 3 && isASCIIHexDigit(p
[1]) && isASCIIHexDigit(p
[2])) {
86 const char b0
= Lexer
<CharType
>::convertHex(p
[1], p
[2]);
87 const int sequenceLen
= UTF8SequenceLength(b0
);
88 if (sequenceLen
&& k
<= length
- sequenceLen
* 3) {
89 charLen
= sequenceLen
* 3;
92 for (int i
= 1; i
< sequenceLen
; ++i
) {
93 const CharType
* q
= p
+ i
* 3;
94 if (q
[0] == '%' && isASCIIHexDigit(q
[1]) && isASCIIHexDigit(q
[2]))
95 sequence
[i
] = Lexer
<CharType
>::convertHex(q
[1], q
[2]);
102 sequence
[sequenceLen
] = 0;
103 const int character
= decodeUTF8Sequence(sequence
);
104 if (character
< 0 || character
>= 0x110000)
106 else if (character
>= 0x10000) {
107 // Convert to surrogate pair.
108 builder
.append(static_cast<UChar
>(0xD800 | ((character
- 0x10000) >> 10)));
109 u
= static_cast<UChar
>(0xDC00 | ((character
- 0x10000) & 0x3FF));
111 u
= static_cast<UChar
>(character
);
117 return throwError(exec
, createURIError(exec
, "URI error"));
118 // The only case where we don't use "strict" mode is the "unescape" function.
119 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
120 if (k
<= length
- 6 && p
[1] == 'u'
121 && isASCIIHexDigit(p
[2]) && isASCIIHexDigit(p
[3])
122 && isASCIIHexDigit(p
[4]) && isASCIIHexDigit(p
[5])) {
124 u
= Lexer
<UChar
>::convertUnicode(p
[2], p
[3], p
[4], p
[5]);
127 if (charLen
&& (u
== 0 || u
>= 128 || !strchr(doNotUnescape
, u
))) {
129 builder
.append(static_cast<LChar
>(u
));
139 return builder
.build(exec
);
142 static JSValue
decode(ExecState
* exec
, const char* doNotUnescape
, bool strict
)
144 JSStringBuilder builder
;
145 UString str
= exec
->argument(0).toString(exec
)->value(exec
);
148 return decode(exec
, str
.characters8(), str
.length(), doNotUnescape
, strict
);
149 return decode(exec
, str
.characters16(), str
.length(), doNotUnescape
, strict
);
152 bool isStrWhiteSpace(UChar c
)
155 // ECMA-262-5th 7.2 & 7.3
168 return c
> 0xff && isSeparatorSpace(c
);
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
, int 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 double parseIntOverflow(const UChar
* s
, int 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
;
233 template <typename CharType
>
235 static double parseInt(const UString
& s
, const CharType
* data
, int radix
)
237 // 1. Let inputString be ToString(string).
238 // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
239 // StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
240 // space.) If inputString does not contain any such characters, let S be the empty string.
241 int length
= s
.length();
243 while (p
< length
&& isStrWhiteSpace(data
[p
]))
247 // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
248 // 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.
253 else if (data
[p
] == '-') {
259 // 6. Let R = ToInt32(radix).
260 // 7. Let stripPrefix be true.
262 // b. If R != 16, let stripPrefix be false.
265 // 10. If stripPrefix is true, then
266 // a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
267 // then remove the first two characters from S and let R = 16.
268 // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
269 // consisting of all characters before the first such character; otherwise, let Z be S.
270 if ((radix
== 0 || radix
== 16) && length
- p
>= 2 && data
[p
] == '0' && (data
[p
+ 1] == 'x' || data
[p
+ 1] == 'X')) {
273 } else if (radix
== 0)
276 // 8.a If R < 2 or R > 36, then return NaN.
277 if (radix
< 2 || radix
> 36)
278 return std::numeric_limits
<double>::quiet_NaN();
280 // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
281 // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
282 // digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
283 // and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
284 // mathematical integer value that is represented by Z in radix-R notation.)
285 // 14. Let number be the Number value for mathInt.
286 int firstDigitPosition
= p
;
287 bool sawDigit
= false;
290 int digit
= parseDigit(data
[p
], radix
);
299 // 12. If Z is empty, return NaN.
301 return std::numeric_limits
<double>::quiet_NaN();
303 // Alternate code path for certain large numbers.
304 if (number
>= mantissaOverflowLowerBound
) {
307 number
= parseDouble(s
.characters() + firstDigitPosition
, p
- firstDigitPosition
, parsedLength
);
308 } else if (radix
== 2 || radix
== 4 || radix
== 8 || radix
== 16 || radix
== 32)
309 number
= parseIntOverflow(s
.substringSharingImpl(firstDigitPosition
, p
- firstDigitPosition
).utf8().data(), p
- firstDigitPosition
, radix
);
312 // 15. Return sign x number.
313 return sign
* number
;
316 static double parseInt(const UString
& s
, int radix
)
319 return parseInt(s
, s
.characters8(), radix
);
320 return parseInt(s
, s
.characters16(), radix
);
323 static const int SizeOfInfinity
= 8;
325 template <typename CharType
>
326 static bool isInfinity(const CharType
* data
, const CharType
* end
)
328 return (end
- data
) >= SizeOfInfinity
339 // See ecma-262 9.3.1
340 template <typename CharType
>
341 static double jsHexIntegerLiteral(const CharType
*& data
, const CharType
* end
)
345 const CharType
* firstDigitPosition
= data
;
348 number
= number
* 16 + toASCIIHexValue(*data
);
352 if (!isASCIIHexDigit(*data
))
355 if (number
>= mantissaOverflowLowerBound
)
356 number
= parseIntOverflow(firstDigitPosition
, data
- firstDigitPosition
, 16);
361 // See ecma-262 9.3.1
362 template <typename CharType
>
363 static double jsStrDecimalLiteral(const CharType
*& data
, const CharType
* end
)
368 double number
= parseDouble(data
, end
- data
, parsedLength
);
370 data
+= parsedLength
;
374 // Check for [+-]?Infinity
377 if (isInfinity(data
, end
)) {
378 data
+= SizeOfInfinity
;
379 return std::numeric_limits
<double>::infinity();
384 if (isInfinity(data
+ 1, end
)) {
385 data
+= SizeOfInfinity
+ 1;
386 return std::numeric_limits
<double>::infinity();
391 if (isInfinity(data
+ 1, end
)) {
392 data
+= SizeOfInfinity
+ 1;
393 return -std::numeric_limits
<double>::infinity();
399 return std::numeric_limits
<double>::quiet_NaN();
402 template <typename CharType
>
403 static double toDouble(const CharType
* characters
, unsigned size
)
405 const CharType
* endCharacters
= characters
+ size
;
407 // Skip leading white space.
408 for (; characters
< endCharacters
; ++characters
) {
409 if (!isStrWhiteSpace(*characters
))
414 if (characters
== endCharacters
)
418 if (characters
[0] == '0' && characters
+ 2 < endCharacters
&& (characters
[1] | 0x20) == 'x' && isASCIIHexDigit(characters
[2]))
419 number
= jsHexIntegerLiteral(characters
, endCharacters
);
421 number
= jsStrDecimalLiteral(characters
, endCharacters
);
423 // Allow trailing white space.
424 for (; characters
< endCharacters
; ++characters
) {
425 if (!isStrWhiteSpace(*characters
))
428 if (characters
!= endCharacters
)
429 return std::numeric_limits
<double>::quiet_NaN();
434 // See ecma-262 9.3.1
435 double jsToNumber(const UString
& s
)
437 unsigned size
= s
.length();
443 if (isStrWhiteSpace(c
))
445 return std::numeric_limits
<double>::quiet_NaN();
449 return toDouble(s
.characters8(), size
);
450 return toDouble(s
.characters16(), size
);
453 static double parseFloat(const UString
& s
)
455 unsigned size
= s
.length();
461 return std::numeric_limits
<double>::quiet_NaN();
465 const LChar
* data
= s
.characters8();
466 const LChar
* end
= data
+ size
;
468 // Skip leading white space.
469 for (; data
< end
; ++data
) {
470 if (!isStrWhiteSpace(*data
))
476 return std::numeric_limits
<double>::quiet_NaN();
478 return jsStrDecimalLiteral(data
, end
);
481 const UChar
* data
= s
.characters16();
482 const UChar
* end
= data
+ size
;
484 // Skip leading white space.
485 for (; data
< end
; ++data
) {
486 if (!isStrWhiteSpace(*data
))
492 return std::numeric_limits
<double>::quiet_NaN();
494 return jsStrDecimalLiteral(data
, end
);
497 EncodedJSValue JSC_HOST_CALL
globalFuncEval(ExecState
* exec
)
499 JSObject
* thisObject
= exec
->hostThisValue().toThisObject(exec
);
500 JSObject
* unwrappedObject
= thisObject
->unwrappedObject();
501 if (!unwrappedObject
->isGlobalObject() || jsCast
<JSGlobalObject
*>(unwrappedObject
)->evalFunction() != exec
->callee())
502 return throwVMError(exec
, createEvalError(exec
, "The \"this\" value passed to eval must be the global object from which eval originated"));
504 JSValue x
= exec
->argument(0);
506 return JSValue::encode(x
);
508 UString s
= x
.toString(exec
)->value(exec
);
511 LiteralParser
<LChar
> preparser(exec
, s
.characters8(), s
.length(), NonStrictJSON
);
512 if (JSValue parsedObject
= preparser
.tryLiteralParse())
513 return JSValue::encode(parsedObject
);
515 LiteralParser
<UChar
> preparser(exec
, s
.characters16(), s
.length(), NonStrictJSON
);
516 if (JSValue parsedObject
= preparser
.tryLiteralParse())
517 return JSValue::encode(parsedObject
);
520 EvalExecutable
* eval
= EvalExecutable::create(exec
, makeSource(s
), false);
521 JSObject
* error
= eval
->compile(exec
, jsCast
<JSGlobalObject
*>(unwrappedObject
)->globalScopeChain());
523 return throwVMError(exec
, error
);
525 return JSValue::encode(exec
->interpreter()->execute(eval
, exec
, thisObject
, jsCast
<JSGlobalObject
*>(unwrappedObject
)->globalScopeChain()));
528 EncodedJSValue JSC_HOST_CALL
globalFuncParseInt(ExecState
* exec
)
530 JSValue value
= exec
->argument(0);
531 JSValue radixValue
= exec
->argument(1);
533 // Optimized handling for numbers:
534 // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
535 // results in a truncation to integer. In the case of -0, this is converted to 0.
537 // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
538 // however these values cannot be trivially truncated to int since 10^21 exceeds
539 // even the int64_t range. Negative numbers are a little trickier, the case for
540 // values in the range -10^21 < n <= -1 are similar to those for integer, but
541 // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
542 static const double tenToTheMinus6
= 0.000001;
543 static const double intMaxPlusOne
= 2147483648.0;
544 if (value
.isNumber()) {
545 double n
= value
.asNumber();
546 if (((n
< intMaxPlusOne
&& n
>= tenToTheMinus6
) || !n
) && radixValue
.isUndefinedOrNull())
547 return JSValue::encode(jsNumber(static_cast<int32_t>(n
)));
550 // If ToString throws, we shouldn't call ToInt32.
551 UString s
= value
.toString(exec
)->value(exec
);
552 if (exec
->hadException())
553 return JSValue::encode(jsUndefined());
555 return JSValue::encode(jsNumber(parseInt(s
, radixValue
.toInt32(exec
))));
558 EncodedJSValue JSC_HOST_CALL
globalFuncParseFloat(ExecState
* exec
)
560 return JSValue::encode(jsNumber(parseFloat(exec
->argument(0).toString(exec
)->value(exec
))));
563 EncodedJSValue JSC_HOST_CALL
globalFuncIsNaN(ExecState
* exec
)
565 return JSValue::encode(jsBoolean(isnan(exec
->argument(0).toNumber(exec
))));
568 EncodedJSValue JSC_HOST_CALL
globalFuncIsFinite(ExecState
* exec
)
570 double n
= exec
->argument(0).toNumber(exec
);
571 return JSValue::encode(jsBoolean(isfinite(n
)));
574 EncodedJSValue JSC_HOST_CALL
globalFuncDecodeURI(ExecState
* exec
)
576 static const char do_not_unescape_when_decoding_URI
[] =
579 return JSValue::encode(decode(exec
, do_not_unescape_when_decoding_URI
, true));
582 EncodedJSValue JSC_HOST_CALL
globalFuncDecodeURIComponent(ExecState
* exec
)
584 return JSValue::encode(decode(exec
, "", true));
587 EncodedJSValue JSC_HOST_CALL
globalFuncEncodeURI(ExecState
* exec
)
589 static const char do_not_escape_when_encoding_URI
[] =
590 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
591 "abcdefghijklmnopqrstuvwxyz"
593 "!#$&'()*+,-./:;=?@_~";
595 return JSValue::encode(encode(exec
, do_not_escape_when_encoding_URI
));
598 EncodedJSValue JSC_HOST_CALL
globalFuncEncodeURIComponent(ExecState
* exec
)
600 static const char do_not_escape_when_encoding_URI_component
[] =
601 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
602 "abcdefghijklmnopqrstuvwxyz"
606 return JSValue::encode(encode(exec
, do_not_escape_when_encoding_URI_component
));
609 EncodedJSValue JSC_HOST_CALL
globalFuncEscape(ExecState
* exec
)
611 static const char do_not_escape
[] =
612 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
613 "abcdefghijklmnopqrstuvwxyz"
617 JSStringBuilder builder
;
618 UString str
= exec
->argument(0).toString(exec
)->value(exec
);
620 const LChar
* c
= str
.characters8();
621 for (unsigned k
= 0; k
< str
.length(); k
++, c
++) {
623 if (u
&& strchr(do_not_escape
, static_cast<char>(u
)))
624 builder
.append(c
, 1);
627 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
632 return JSValue::encode(builder
.build(exec
));
635 const UChar
* c
= str
.characters16();
636 for (unsigned k
= 0; k
< str
.length(); k
++, c
++) {
640 snprintf(tmp
, sizeof(tmp
), "%%u%04X", u
);
642 } else if (u
!= 0 && strchr(do_not_escape
, static_cast<char>(u
)))
643 builder
.append(c
, 1);
646 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
651 return JSValue::encode(builder
.build(exec
));
654 EncodedJSValue JSC_HOST_CALL
globalFuncUnescape(ExecState
* exec
)
656 UStringBuilder builder
;
657 UString str
= exec
->argument(0).toString(exec
)->value(exec
);
659 int len
= str
.length();
662 const LChar
* characters
= str
.characters8();
663 LChar convertedLChar
;
665 const LChar
* c
= characters
+ k
;
666 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
667 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
668 builder
.append(Lexer
<UChar
>::convertUnicode(c
[2], c
[3], c
[4], c
[5]));
672 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
673 convertedLChar
= LChar(Lexer
<LChar
>::convertHex(c
[1], c
[2]));
681 const UChar
* characters
= str
.characters16();
684 const UChar
* c
= characters
+ k
;
685 UChar convertedUChar
;
686 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
687 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
688 convertedUChar
= Lexer
<UChar
>::convertUnicode(c
[2], c
[3], c
[4], c
[5]);
692 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
693 convertedUChar
= UChar(Lexer
<UChar
>::convertHex(c
[1], c
[2]));
702 return JSValue::encode(jsString(exec
, builder
.toUString()));
705 EncodedJSValue JSC_HOST_CALL
globalFuncThrowTypeError(ExecState
* exec
)
707 return throwVMTypeError(exec
);
710 EncodedJSValue JSC_HOST_CALL
globalFuncProtoGetter(ExecState
* exec
)
712 if (!exec
->thisValue().isObject())
713 return JSValue::encode(exec
->thisValue().synthesizePrototype(exec
));
715 JSObject
* thisObject
= asObject(exec
->thisValue());
716 if (!thisObject
->allowsAccessFrom(exec
->trueCallerFrame()))
717 return JSValue::encode(jsUndefined());
719 return JSValue::encode(thisObject
->prototype());
722 EncodedJSValue JSC_HOST_CALL
globalFuncProtoSetter(ExecState
* exec
)
724 JSValue value
= exec
->argument(0);
726 // Setting __proto__ of a primitive should have no effect.
727 if (!exec
->thisValue().isObject())
728 return JSValue::encode(jsUndefined());
730 JSObject
* thisObject
= asObject(exec
->thisValue());
731 if (!thisObject
->allowsAccessFrom(exec
->trueCallerFrame()))
732 return JSValue::encode(jsUndefined());
734 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
735 if (!value
.isObject() && !value
.isNull())
736 return JSValue::encode(jsUndefined());
738 if (!thisObject
->isExtensible())
739 return throwVMError(exec
, createTypeError(exec
, StrictModeReadonlyPropertyWriteError
));
741 if (!thisObject
->setPrototypeWithCycleCheck(exec
->globalData(), value
))
742 throwError(exec
, createError(exec
, "cyclic __proto__ value"));
743 return JSValue::encode(jsUndefined());