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 "Operations.h"
42 #include <wtf/ASCIICType.h>
43 #include <wtf/Assertions.h>
44 #include <wtf/MathExtras.h>
45 #include <wtf/StringExtras.h>
46 #include <wtf/text/StringBuilder.h>
47 #include <wtf/unicode/UTF8.h>
50 using namespace Unicode
;
54 static JSValue
encode(ExecState
* exec
, const char* doNotEscape
)
56 CString cstr
= exec
->argument(0).toString(exec
)->value(exec
).utf8(String::StrictConversion
);
58 return throwError(exec
, createURIError(exec
, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
60 JSStringBuilder builder
;
61 const char* p
= cstr
.data();
62 for (size_t k
= 0; k
< cstr
.length(); k
++, p
++) {
64 if (c
&& strchr(doNotEscape
, c
))
68 snprintf(tmp
, sizeof(tmp
), "%%%02X", static_cast<unsigned char>(c
));
72 return builder
.build(exec
);
75 template <typename CharType
>
77 static JSValue
decode(ExecState
* exec
, const CharType
* characters
, int length
, const char* doNotUnescape
, bool strict
)
79 JSStringBuilder builder
;
83 const CharType
* p
= characters
+ k
;
87 if (k
<= length
- 3 && isASCIIHexDigit(p
[1]) && isASCIIHexDigit(p
[2])) {
88 const char b0
= Lexer
<CharType
>::convertHex(p
[1], p
[2]);
89 const int sequenceLen
= UTF8SequenceLength(b0
);
90 if (sequenceLen
&& k
<= length
- sequenceLen
* 3) {
91 charLen
= sequenceLen
* 3;
94 for (int i
= 1; i
< sequenceLen
; ++i
) {
95 const CharType
* q
= p
+ i
* 3;
96 if (q
[0] == '%' && isASCIIHexDigit(q
[1]) && isASCIIHexDigit(q
[2]))
97 sequence
[i
] = Lexer
<CharType
>::convertHex(q
[1], q
[2]);
104 sequence
[sequenceLen
] = 0;
105 const int character
= decodeUTF8Sequence(sequence
);
106 if (character
< 0 || character
>= 0x110000)
108 else if (character
>= 0x10000) {
109 // Convert to surrogate pair.
110 builder
.append(static_cast<UChar
>(0xD800 | ((character
- 0x10000) >> 10)));
111 u
= static_cast<UChar
>(0xDC00 | ((character
- 0x10000) & 0x3FF));
113 u
= static_cast<UChar
>(character
);
119 return throwError(exec
, createURIError(exec
, ASCIILiteral("URI error")));
120 // The only case where we don't use "strict" mode is the "unescape" function.
121 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
122 if (k
<= length
- 6 && p
[1] == 'u'
123 && isASCIIHexDigit(p
[2]) && isASCIIHexDigit(p
[3])
124 && isASCIIHexDigit(p
[4]) && isASCIIHexDigit(p
[5])) {
126 u
= Lexer
<UChar
>::convertUnicode(p
[2], p
[3], p
[4], p
[5]);
129 if (charLen
&& (u
== 0 || u
>= 128 || !strchr(doNotUnescape
, u
))) {
131 builder
.append(static_cast<LChar
>(u
));
141 return builder
.build(exec
);
144 static JSValue
decode(ExecState
* exec
, const char* doNotUnescape
, bool strict
)
146 JSStringBuilder builder
;
147 String str
= exec
->argument(0).toString(exec
)->value(exec
);
150 return decode(exec
, str
.characters8(), str
.length(), doNotUnescape
, strict
);
151 return decode(exec
, str
.characters16(), str
.length(), doNotUnescape
, strict
);
154 bool isStrWhiteSpace(UChar c
)
157 // ECMA-262-5th 7.2 & 7.3
170 return c
> 0xff && isSeparatorSpace(c
);
174 static int parseDigit(unsigned short c
, int radix
)
178 if (c
>= '0' && c
<= '9')
180 else if (c
>= 'A' && c
<= 'Z')
181 digit
= c
- 'A' + 10;
182 else if (c
>= 'a' && c
<= 'z')
183 digit
= c
- 'a' + 10;
190 double parseIntOverflow(const LChar
* s
, int length
, int radix
)
193 double radixMultiplier
= 1.0;
195 for (const LChar
* p
= s
+ length
- 1; p
>= s
; p
--) {
196 if (radixMultiplier
== std::numeric_limits
<double>::infinity()) {
198 number
= std::numeric_limits
<double>::infinity();
202 int digit
= parseDigit(*p
, radix
);
203 number
+= digit
* radixMultiplier
;
206 radixMultiplier
*= radix
;
212 double parseIntOverflow(const UChar
* s
, int length
, int radix
)
215 double radixMultiplier
= 1.0;
217 for (const UChar
* p
= s
+ length
- 1; p
>= s
; p
--) {
218 if (radixMultiplier
== std::numeric_limits
<double>::infinity()) {
220 number
= std::numeric_limits
<double>::infinity();
224 int digit
= parseDigit(*p
, radix
);
225 number
+= digit
* radixMultiplier
;
228 radixMultiplier
*= radix
;
235 template <typename CharType
>
237 static double parseInt(const String
& s
, const CharType
* data
, int radix
)
239 // 1. Let inputString be ToString(string).
240 // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
241 // StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
242 // space.) If inputString does not contain any such characters, let S be the empty string.
243 int length
= s
.length();
245 while (p
< length
&& isStrWhiteSpace(data
[p
]))
249 // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
250 // 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.
255 else if (data
[p
] == '-') {
261 // 6. Let R = ToInt32(radix).
262 // 7. Let stripPrefix be true.
264 // b. If R != 16, let stripPrefix be false.
267 // 10. If stripPrefix is true, then
268 // a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
269 // then remove the first two characters from S and let R = 16.
270 // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
271 // consisting of all characters before the first such character; otherwise, let Z be S.
272 if ((radix
== 0 || radix
== 16) && length
- p
>= 2 && data
[p
] == '0' && (data
[p
+ 1] == 'x' || data
[p
+ 1] == 'X')) {
275 } else if (radix
== 0)
278 // 8.a If R < 2 or R > 36, then return NaN.
279 if (radix
< 2 || radix
> 36)
282 // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
283 // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
284 // digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
285 // and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
286 // mathematical integer value that is represented by Z in radix-R notation.)
287 // 14. Let number be the Number value for mathInt.
288 int firstDigitPosition
= p
;
289 bool sawDigit
= false;
292 int digit
= parseDigit(data
[p
], radix
);
301 // 12. If Z is empty, return NaN.
305 // Alternate code path for certain large numbers.
306 if (number
>= mantissaOverflowLowerBound
) {
309 number
= parseDouble(s
.characters() + firstDigitPosition
, p
- firstDigitPosition
, parsedLength
);
310 } else if (radix
== 2 || radix
== 4 || radix
== 8 || radix
== 16 || radix
== 32)
311 number
= parseIntOverflow(s
.substringSharingImpl(firstDigitPosition
, p
- firstDigitPosition
).utf8().data(), p
- firstDigitPosition
, radix
);
314 // 15. Return sign x number.
315 return sign
* number
;
318 static double parseInt(const String
& s
, int radix
)
321 return parseInt(s
, s
.characters8(), radix
);
322 return parseInt(s
, s
.characters16(), radix
);
325 static const int SizeOfInfinity
= 8;
327 template <typename CharType
>
328 static bool isInfinity(const CharType
* data
, const CharType
* end
)
330 return (end
- data
) >= SizeOfInfinity
341 // See ecma-262 9.3.1
342 template <typename CharType
>
343 static double jsHexIntegerLiteral(const CharType
*& data
, const CharType
* end
)
347 const CharType
* firstDigitPosition
= data
;
350 number
= number
* 16 + toASCIIHexValue(*data
);
354 if (!isASCIIHexDigit(*data
))
357 if (number
>= mantissaOverflowLowerBound
)
358 number
= parseIntOverflow(firstDigitPosition
, data
- firstDigitPosition
, 16);
363 // See ecma-262 9.3.1
364 template <typename CharType
>
365 static double jsStrDecimalLiteral(const CharType
*& data
, const CharType
* end
)
367 RELEASE_ASSERT(data
< end
);
370 double number
= parseDouble(data
, end
- data
, parsedLength
);
372 data
+= parsedLength
;
376 // Check for [+-]?Infinity
379 if (isInfinity(data
, end
)) {
380 data
+= SizeOfInfinity
;
381 return std::numeric_limits
<double>::infinity();
386 if (isInfinity(data
+ 1, end
)) {
387 data
+= SizeOfInfinity
+ 1;
388 return std::numeric_limits
<double>::infinity();
393 if (isInfinity(data
+ 1, end
)) {
394 data
+= SizeOfInfinity
+ 1;
395 return -std::numeric_limits
<double>::infinity();
404 template <typename CharType
>
405 static double toDouble(const CharType
* characters
, unsigned size
)
407 const CharType
* endCharacters
= characters
+ size
;
409 // Skip leading white space.
410 for (; characters
< endCharacters
; ++characters
) {
411 if (!isStrWhiteSpace(*characters
))
416 if (characters
== endCharacters
)
420 if (characters
[0] == '0' && characters
+ 2 < endCharacters
&& (characters
[1] | 0x20) == 'x' && isASCIIHexDigit(characters
[2]))
421 number
= jsHexIntegerLiteral(characters
, endCharacters
);
423 number
= jsStrDecimalLiteral(characters
, endCharacters
);
425 // Allow trailing white space.
426 for (; characters
< endCharacters
; ++characters
) {
427 if (!isStrWhiteSpace(*characters
))
430 if (characters
!= endCharacters
)
436 // See ecma-262 9.3.1
437 double jsToNumber(const String
& s
)
439 unsigned size
= s
.length();
445 if (isStrWhiteSpace(c
))
451 return toDouble(s
.characters8(), size
);
452 return toDouble(s
.characters16(), size
);
455 static double parseFloat(const String
& s
)
457 unsigned size
= s
.length();
467 const LChar
* data
= s
.characters8();
468 const LChar
* end
= data
+ size
;
470 // Skip leading white space.
471 for (; data
< end
; ++data
) {
472 if (!isStrWhiteSpace(*data
))
480 return jsStrDecimalLiteral(data
, end
);
483 const UChar
* data
= s
.characters16();
484 const UChar
* end
= data
+ size
;
486 // Skip leading white space.
487 for (; data
< end
; ++data
) {
488 if (!isStrWhiteSpace(*data
))
496 return jsStrDecimalLiteral(data
, end
);
499 EncodedJSValue JSC_HOST_CALL
globalFuncEval(ExecState
* exec
)
501 JSValue x
= exec
->argument(0);
503 return JSValue::encode(x
);
505 String s
= x
.toString(exec
)->value(exec
);
508 LiteralParser
<LChar
> preparser(exec
, s
.characters8(), s
.length(), NonStrictJSON
);
509 if (JSValue parsedObject
= preparser
.tryLiteralParse())
510 return JSValue::encode(parsedObject
);
512 LiteralParser
<UChar
> preparser(exec
, s
.characters16(), s
.length(), NonStrictJSON
);
513 if (JSValue parsedObject
= preparser
.tryLiteralParse())
514 return JSValue::encode(parsedObject
);
517 JSGlobalObject
* calleeGlobalObject
= exec
->callee()->globalObject();
518 EvalExecutable
* eval
= EvalExecutable::create(exec
, exec
->vm().codeCache(), makeSource(s
), false);
519 JSObject
* error
= eval
->compile(exec
, calleeGlobalObject
);
521 return throwVMError(exec
, error
);
523 return JSValue::encode(exec
->interpreter()->execute(eval
, exec
, calleeGlobalObject
->globalThis(), calleeGlobalObject
));
526 EncodedJSValue JSC_HOST_CALL
globalFuncParseInt(ExecState
* exec
)
528 JSValue value
= exec
->argument(0);
529 JSValue radixValue
= exec
->argument(1);
531 // Optimized handling for numbers:
532 // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
533 // results in a truncation to integer. In the case of -0, this is converted to 0.
535 // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
536 // however these values cannot be trivially truncated to int since 10^21 exceeds
537 // even the int64_t range. Negative numbers are a little trickier, the case for
538 // values in the range -10^21 < n <= -1 are similar to those for integer, but
539 // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
540 static const double tenToTheMinus6
= 0.000001;
541 static const double intMaxPlusOne
= 2147483648.0;
542 if (value
.isNumber()) {
543 double n
= value
.asNumber();
544 if (((n
< intMaxPlusOne
&& n
>= tenToTheMinus6
) || !n
) && radixValue
.isUndefinedOrNull())
545 return JSValue::encode(jsNumber(static_cast<int32_t>(n
)));
548 // If ToString throws, we shouldn't call ToInt32.
549 String s
= value
.toString(exec
)->value(exec
);
550 if (exec
->hadException())
551 return JSValue::encode(jsUndefined());
553 return JSValue::encode(jsNumber(parseInt(s
, radixValue
.toInt32(exec
))));
556 EncodedJSValue JSC_HOST_CALL
globalFuncParseFloat(ExecState
* exec
)
558 return JSValue::encode(jsNumber(parseFloat(exec
->argument(0).toString(exec
)->value(exec
))));
561 EncodedJSValue JSC_HOST_CALL
globalFuncIsNaN(ExecState
* exec
)
563 return JSValue::encode(jsBoolean(std::isnan(exec
->argument(0).toNumber(exec
))));
566 EncodedJSValue JSC_HOST_CALL
globalFuncIsFinite(ExecState
* exec
)
568 double n
= exec
->argument(0).toNumber(exec
);
569 return JSValue::encode(jsBoolean(std::isfinite(n
)));
572 EncodedJSValue JSC_HOST_CALL
globalFuncDecodeURI(ExecState
* exec
)
574 static const char do_not_unescape_when_decoding_URI
[] =
577 return JSValue::encode(decode(exec
, do_not_unescape_when_decoding_URI
, true));
580 EncodedJSValue JSC_HOST_CALL
globalFuncDecodeURIComponent(ExecState
* exec
)
582 return JSValue::encode(decode(exec
, "", true));
585 EncodedJSValue JSC_HOST_CALL
globalFuncEncodeURI(ExecState
* exec
)
587 static const char do_not_escape_when_encoding_URI
[] =
588 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
589 "abcdefghijklmnopqrstuvwxyz"
591 "!#$&'()*+,-./:;=?@_~";
593 return JSValue::encode(encode(exec
, do_not_escape_when_encoding_URI
));
596 EncodedJSValue JSC_HOST_CALL
globalFuncEncodeURIComponent(ExecState
* exec
)
598 static const char do_not_escape_when_encoding_URI_component
[] =
599 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
600 "abcdefghijklmnopqrstuvwxyz"
604 return JSValue::encode(encode(exec
, do_not_escape_when_encoding_URI_component
));
607 EncodedJSValue JSC_HOST_CALL
globalFuncEscape(ExecState
* exec
)
609 static const char do_not_escape
[] =
610 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
611 "abcdefghijklmnopqrstuvwxyz"
615 JSStringBuilder builder
;
616 String str
= exec
->argument(0).toString(exec
)->value(exec
);
618 const LChar
* c
= str
.characters8();
619 for (unsigned k
= 0; k
< str
.length(); k
++, c
++) {
621 if (u
&& strchr(do_not_escape
, static_cast<char>(u
)))
622 builder
.append(c
, 1);
625 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
630 return JSValue::encode(builder
.build(exec
));
633 const UChar
* c
= str
.characters16();
634 for (unsigned k
= 0; k
< str
.length(); k
++, c
++) {
638 snprintf(tmp
, sizeof(tmp
), "%%u%04X", u
);
640 } else if (u
!= 0 && strchr(do_not_escape
, static_cast<char>(u
)))
641 builder
.append(c
, 1);
644 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
649 return JSValue::encode(builder
.build(exec
));
652 EncodedJSValue JSC_HOST_CALL
globalFuncUnescape(ExecState
* exec
)
654 StringBuilder builder
;
655 String str
= exec
->argument(0).toString(exec
)->value(exec
);
657 int len
= str
.length();
660 const LChar
* characters
= str
.characters8();
661 LChar convertedLChar
;
663 const LChar
* c
= characters
+ k
;
664 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
665 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
666 builder
.append(Lexer
<UChar
>::convertUnicode(c
[2], c
[3], c
[4], c
[5]));
670 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
671 convertedLChar
= LChar(Lexer
<LChar
>::convertHex(c
[1], c
[2]));
679 const UChar
* characters
= str
.characters16();
682 const UChar
* c
= characters
+ k
;
683 UChar convertedUChar
;
684 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
685 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
686 convertedUChar
= Lexer
<UChar
>::convertUnicode(c
[2], c
[3], c
[4], c
[5]);
690 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
691 convertedUChar
= UChar(Lexer
<UChar
>::convertHex(c
[1], c
[2]));
700 return JSValue::encode(jsString(exec
, builder
.toString()));
703 EncodedJSValue JSC_HOST_CALL
globalFuncThrowTypeError(ExecState
* exec
)
705 return throwVMTypeError(exec
);
708 EncodedJSValue JSC_HOST_CALL
globalFuncProtoGetter(ExecState
* exec
)
710 if (!exec
->thisValue().isObject())
711 return JSValue::encode(exec
->thisValue().synthesizePrototype(exec
));
713 JSObject
* thisObject
= asObject(exec
->thisValue());
714 if (!thisObject
->allowsAccessFrom(exec
->trueCallerFrame()))
715 return JSValue::encode(jsUndefined());
717 return JSValue::encode(thisObject
->prototype());
720 EncodedJSValue JSC_HOST_CALL
globalFuncProtoSetter(ExecState
* exec
)
722 JSValue value
= exec
->argument(0);
724 // Setting __proto__ of a primitive should have no effect.
725 if (!exec
->thisValue().isObject())
726 return JSValue::encode(jsUndefined());
728 JSObject
* thisObject
= asObject(exec
->thisValue());
729 if (!thisObject
->allowsAccessFrom(exec
->trueCallerFrame()))
730 return JSValue::encode(jsUndefined());
732 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
733 if (!value
.isObject() && !value
.isNull())
734 return JSValue::encode(jsUndefined());
736 if (!thisObject
->isExtensible())
737 return throwVMError(exec
, createTypeError(exec
, StrictModeReadonlyPropertyWriteError
));
739 if (!thisObject
->setPrototypeWithCycleCheck(exec
->vm(), value
))
740 throwError(exec
, createError(exec
, "cyclic __proto__ value"));
741 return JSValue::encode(jsUndefined());