[JSC] Implement isFinite / isNaN in JS and make DFG ToNumber accept non number values
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGlobalObjectFunctions.cpp
1 /*
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, 2016 Apple Inc. All rights reserved.
5  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6  *  Copyright (C) 2007 Maks Orlovich
7  *
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.
12  *
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.
17  *
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.
22  *
23  */
24
25 #include "config.h"
26 #include "JSGlobalObjectFunctions.h"
27
28 #include "CallFrame.h"
29 #include "Interpreter.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
32 #include "JSString.h"
33 #include "JSStringBuilder.h"
34 #include "Lexer.h"
35 #include "LiteralParser.h"
36 #include "Nodes.h"
37 #include "JSCInlines.h"
38 #include "Parser.h"
39 #include "StackVisitor.h"
40 #include <wtf/dtoa.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <wtf/ASCIICType.h>
44 #include <wtf/Assertions.h>
45 #include <wtf/HexNumber.h>
46 #include <wtf/MathExtras.h>
47 #include <wtf/StringExtras.h>
48 #include <wtf/text/StringBuilder.h>
49 #include <wtf/unicode/UTF8.h>
50
51 using namespace WTF;
52 using namespace Unicode;
53
54 namespace JSC {
55
56 template<typename CallbackWhenNoException>
57 static ALWAYS_INLINE typename std::result_of<CallbackWhenNoException(JSString::SafeView&)>::type toSafeView(ExecState* exec, JSValue value, CallbackWhenNoException callback)
58 {
59     JSString* string = value.toStringOrNull(exec);
60     if (UNLIKELY(!string))
61         return { };
62     JSString::SafeView view = string->view(exec);
63     return callback(view);
64 }
65
66 template<unsigned charactersCount>
67 static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount])
68 {
69     static_assert(charactersCount > 0, "Since string literal is null terminated, characterCount is always larger than 0");
70     Bitmap<256> bitmap;
71     for (unsigned i = 0; i < charactersCount - 1; ++i)
72         bitmap.set(characters[i]);
73     return bitmap;
74 }
75
76 template<typename CharacterType>
77 static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape, const CharacterType* characters, unsigned length)
78 {
79     // 18.2.6.1.1 Runtime Semantics: Encode ( string, unescapedSet )
80     // https://tc39.github.io/ecma262/#sec-encode
81
82     auto throwException = [exec] {
83         return exec->vm().throwException(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
84     };
85
86     StringBuilder builder;
87     builder.reserveCapacity(length);
88
89     // 4. Repeat
90     auto* end = characters + length;
91     for (auto* cursor = characters; cursor != end; ++cursor) {
92         auto character = *cursor;
93
94         // 4-c. If C is in unescapedSet, then
95         if (character < doNotEscape.size() && doNotEscape.get(character)) {
96             // 4-c-i. Let S be a String containing only the code unit C.
97             // 4-c-ii. Let R be a new String value computed by concatenating the previous value of R and S.
98             builder.append(static_cast<LChar>(character));
99             continue;
100         }
101
102         // 4-d-i. If the code unit value of C is not less than 0xDC00 and not greater than 0xDFFF, throw a URIError exception.
103         if (U16_IS_TRAIL(character))
104             return throwException();
105
106         // 4-d-ii. If the code unit value of C is less than 0xD800 or greater than 0xDBFF, then
107         // 4-d-ii-1. Let V be the code unit value of C.
108         UChar32 codePoint;
109         if (!U16_IS_LEAD(character))
110             codePoint = character;
111         else {
112             // 4-d-iii. Else,
113             // 4-d-iii-1. Increase k by 1.
114             ++cursor;
115
116             // 4-d-iii-2. If k equals strLen, throw a URIError exception.
117             if (cursor == end)
118                 return throwException();
119
120             // 4-d-iii-3. Let kChar be the code unit value of the code unit at index k within string.
121             auto trail = *cursor;
122
123             // 4-d-iii-4. If kChar is less than 0xDC00 or greater than 0xDFFF, throw a URIError exception.
124             if (!U16_IS_TRAIL(trail))
125                 return throwException();
126
127             // 4-d-iii-5. Let V be UTF16Decode(C, kChar).
128             codePoint = U16_GET_SUPPLEMENTARY(character, trail);
129         }
130
131         // 4-d-iv. Let Octets be the array of octets resulting by applying the UTF-8 transformation to V, and let L be the array size.
132         LChar utf8OctetsBuffer[U8_MAX_LENGTH];
133         unsigned utf8Length = 0;
134         // We can use U8_APPEND_UNSAFE here since codePoint is either
135         // 1. non surrogate one, correct code point.
136         // 2. correct code point generated from validated lead and trail surrogates.
137         U8_APPEND_UNSAFE(utf8OctetsBuffer, utf8Length, codePoint);
138
139         // 4-d-v. Let j be 0.
140         // 4-d-vi. Repeat, while j < L
141         for (unsigned index = 0; index < utf8Length; ++index) {
142             // 4-d-vi-1. Let jOctet be the value at index j within Octets.
143             // 4-d-vi-2. Let S be a String containing three code units "%XY" where XY are two uppercase hexadecimal digits encoding the value of jOctet.
144             // 4-d-vi-3. Let R be a new String value computed by concatenating the previous value of R and S.
145             builder.append(static_cast<LChar>('%'));
146             appendByteAsHex(utf8OctetsBuffer[index], builder);
147         }
148     }
149
150     return jsString(exec, builder.toString());
151 }
152
153 static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape)
154 {
155     return toSafeView(exec, exec->argument(0), [&] (JSString::SafeView& view) {
156         if (view.is8Bit())
157             return encode(exec, doNotEscape, view.characters8(), view.length());
158         return encode(exec, doNotEscape, view.characters16(), view.length());
159     });
160 }
161
162 template <typename CharType>
163 ALWAYS_INLINE
164 static JSValue decode(ExecState* exec, const CharType* characters, int length, const Bitmap<256>& doNotUnescape, bool strict)
165 {
166     JSStringBuilder builder;
167     int k = 0;
168     UChar u = 0;
169     while (k < length) {
170         const CharType* p = characters + k;
171         CharType c = *p;
172         if (c == '%') {
173             int charLen = 0;
174             if (k <= length - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
175                 const char b0 = Lexer<CharType>::convertHex(p[1], p[2]);
176                 const int sequenceLen = UTF8SequenceLength(b0);
177                 if (sequenceLen && k <= length - sequenceLen * 3) {
178                     charLen = sequenceLen * 3;
179                     char sequence[5];
180                     sequence[0] = b0;
181                     for (int i = 1; i < sequenceLen; ++i) {
182                         const CharType* q = p + i * 3;
183                         if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
184                             sequence[i] = Lexer<CharType>::convertHex(q[1], q[2]);
185                         else {
186                             charLen = 0;
187                             break;
188                         }
189                     }
190                     if (charLen != 0) {
191                         sequence[sequenceLen] = 0;
192                         const int character = decodeUTF8Sequence(sequence);
193                         if (character < 0 || character >= 0x110000)
194                             charLen = 0;
195                         else if (character >= 0x10000) {
196                             // Convert to surrogate pair.
197                             builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
198                             u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
199                         } else
200                             u = static_cast<UChar>(character);
201                     }
202                 }
203             }
204             if (charLen == 0) {
205                 if (strict)
206                     return exec->vm().throwException(exec, createURIError(exec, ASCIILiteral("URI error")));
207                 // The only case where we don't use "strict" mode is the "unescape" function.
208                 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
209                 if (k <= length - 6 && p[1] == 'u'
210                         && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
211                         && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
212                     charLen = 6;
213                     u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
214                 }
215             }
216             if (charLen && (u >= 128 || !doNotUnescape.get(static_cast<LChar>(u)))) {
217                 builder.append(u);
218                 k += charLen;
219                 continue;
220             }
221         }
222         k++;
223         builder.append(c);
224     }
225     return builder.build(exec);
226 }
227
228 static JSValue decode(ExecState* exec, const Bitmap<256>& doNotUnescape, bool strict)
229 {
230     return toSafeView(exec, exec->argument(0), [&] (JSString::SafeView& view) {
231         if (view.is8Bit())
232             return decode(exec, view.characters8(), view.length(), doNotUnescape, strict);
233         return decode(exec, view.characters16(), view.length(), doNotUnescape, strict);
234     });
235 }
236
237 bool isStrWhiteSpace(UChar c)
238 {
239     switch (c) {
240         // ECMA-262-5th 7.2 & 7.3
241         case 0x0009:
242         case 0x000A:
243         case 0x000B:
244         case 0x000C:
245         case 0x000D:
246         case 0x0020:
247         case 0x00A0:
248         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.
249         case 0x2028:
250         case 0x2029:
251         case 0xFEFF:
252             return true;
253         default:
254             return c > 0xFF && u_charType(c) == U_SPACE_SEPARATOR;
255     }
256 }
257
258 static int parseDigit(unsigned short c, int radix)
259 {
260     int digit = -1;
261
262     if (c >= '0' && c <= '9')
263         digit = c - '0';
264     else if (c >= 'A' && c <= 'Z')
265         digit = c - 'A' + 10;
266     else if (c >= 'a' && c <= 'z')
267         digit = c - 'a' + 10;
268
269     if (digit >= radix)
270         return -1;
271     return digit;
272 }
273
274 double parseIntOverflow(const LChar* s, unsigned length, int radix)
275 {
276     double number = 0.0;
277     double radixMultiplier = 1.0;
278
279     for (const LChar* p = s + length - 1; p >= s; p--) {
280         if (radixMultiplier == std::numeric_limits<double>::infinity()) {
281             if (*p != '0') {
282                 number = std::numeric_limits<double>::infinity();
283                 break;
284             }
285         } else {
286             int digit = parseDigit(*p, radix);
287             number += digit * radixMultiplier;
288         }
289
290         radixMultiplier *= radix;
291     }
292
293     return number;
294 }
295
296 static double parseIntOverflow(const UChar* s, unsigned length, int radix)
297 {
298     double number = 0.0;
299     double radixMultiplier = 1.0;
300
301     for (const UChar* p = s + length - 1; p >= s; p--) {
302         if (radixMultiplier == std::numeric_limits<double>::infinity()) {
303             if (*p != '0') {
304                 number = std::numeric_limits<double>::infinity();
305                 break;
306             }
307         } else {
308             int digit = parseDigit(*p, radix);
309             number += digit * radixMultiplier;
310         }
311
312         radixMultiplier *= radix;
313     }
314
315     return number;
316 }
317
318 static double parseIntOverflow(StringView string, int radix)
319 {
320     if (string.is8Bit())
321         return parseIntOverflow(string.characters8(), string.length(), radix);
322     return parseIntOverflow(string.characters16(), string.length(), radix);
323 }
324
325 // ES5.1 15.1.2.2
326 template <typename CharType>
327 ALWAYS_INLINE
328 static double parseInt(StringView s, const CharType* data, int radix)
329 {
330     // 1. Let inputString be ToString(string).
331     // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
332     //    StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
333     //    space.) If inputString does not contain any such characters, let S be the empty string.
334     int length = s.length();
335     int p = 0;
336     while (p < length && isStrWhiteSpace(data[p]))
337         ++p;
338
339     // 3. Let sign be 1.
340     // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
341     // 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.
342     double sign = 1;
343     if (p < length) {
344         if (data[p] == '+')
345             ++p;
346         else if (data[p] == '-') {
347             sign = -1;
348             ++p;
349         }
350     }
351
352     // 6. Let R = ToInt32(radix).
353     // 7. Let stripPrefix be true.
354     // 8. If R != 0,then
355     //   b. If R != 16, let stripPrefix be false.
356     // 9. Else, R == 0
357     //   a. LetR = 10.
358     // 10. If stripPrefix is true, then
359     //   a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
360     //      then remove the first two characters from S and let R = 16.
361     // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
362     //     consisting of all characters before the first such character; otherwise, let Z be S.
363     if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
364         radix = 16;
365         p += 2;
366     } else if (radix == 0)
367         radix = 10;
368
369     // 8.a If R < 2 or R > 36, then return NaN.
370     if (radix < 2 || radix > 36)
371         return PNaN;
372
373     // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
374     //     A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
375     //     digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
376     //     and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
377     //     mathematical integer value that is represented by Z in radix-R notation.)
378     // 14. Let number be the Number value for mathInt.
379     int firstDigitPosition = p;
380     bool sawDigit = false;
381     double number = 0;
382     while (p < length) {
383         int digit = parseDigit(data[p], radix);
384         if (digit == -1)
385             break;
386         sawDigit = true;
387         number *= radix;
388         number += digit;
389         ++p;
390     }
391
392     // 12. If Z is empty, return NaN.
393     if (!sawDigit)
394         return PNaN;
395
396     // Alternate code path for certain large numbers.
397     if (number >= mantissaOverflowLowerBound) {
398         if (radix == 10) {
399             size_t parsedLength;
400             number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength);
401         } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
402             number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix);
403     }
404
405     // 15. Return sign x number.
406     return sign * number;
407 }
408
409 static double parseInt(StringView s, int radix)
410 {
411     if (s.is8Bit())
412         return parseInt(s, s.characters8(), radix);
413     return parseInt(s, s.characters16(), radix);
414 }
415
416 static const int SizeOfInfinity = 8;
417
418 template <typename CharType>
419 static bool isInfinity(const CharType* data, const CharType* end)
420 {
421     return (end - data) >= SizeOfInfinity
422         && data[0] == 'I'
423         && data[1] == 'n'
424         && data[2] == 'f'
425         && data[3] == 'i'
426         && data[4] == 'n'
427         && data[5] == 'i'
428         && data[6] == 't'
429         && data[7] == 'y';
430 }
431
432 // See ecma-262 6th 11.8.3
433 template <typename CharType>
434 static double jsBinaryIntegerLiteral(const CharType*& data, const CharType* end)
435 {
436     // Binary number.
437     data += 2;
438     const CharType* firstDigitPosition = data;
439     double number = 0;
440     while (true) {
441         number = number * 2 + (*data - '0');
442         ++data;
443         if (data == end)
444             break;
445         if (!isASCIIBinaryDigit(*data))
446             break;
447     }
448     if (number >= mantissaOverflowLowerBound)
449         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 2);
450
451     return number;
452 }
453
454 // See ecma-262 6th 11.8.3
455 template <typename CharType>
456 static double jsOctalIntegerLiteral(const CharType*& data, const CharType* end)
457 {
458     // Octal number.
459     data += 2;
460     const CharType* firstDigitPosition = data;
461     double number = 0;
462     while (true) {
463         number = number * 8 + (*data - '0');
464         ++data;
465         if (data == end)
466             break;
467         if (!isASCIIOctalDigit(*data))
468             break;
469     }
470     if (number >= mantissaOverflowLowerBound)
471         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 8);
472     
473     return number;
474 }
475
476 // See ecma-262 6th 11.8.3
477 template <typename CharType>
478 static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
479 {
480     // Hex number.
481     data += 2;
482     const CharType* firstDigitPosition = data;
483     double number = 0;
484     while (true) {
485         number = number * 16 + toASCIIHexValue(*data);
486         ++data;
487         if (data == end)
488             break;
489         if (!isASCIIHexDigit(*data))
490             break;
491     }
492     if (number >= mantissaOverflowLowerBound)
493         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
494
495     return number;
496 }
497
498 // See ecma-262 6th 11.8.3
499 template <typename CharType>
500 static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
501 {
502     RELEASE_ASSERT(data < end);
503
504     size_t parsedLength;
505     double number = parseDouble(data, end - data, parsedLength);
506     if (parsedLength) {
507         data += parsedLength;
508         return number;
509     }
510
511     // Check for [+-]?Infinity
512     switch (*data) {
513     case 'I':
514         if (isInfinity(data, end)) {
515             data += SizeOfInfinity;
516             return std::numeric_limits<double>::infinity();
517         }
518         break;
519
520     case '+':
521         if (isInfinity(data + 1, end)) {
522             data += SizeOfInfinity + 1;
523             return std::numeric_limits<double>::infinity();
524         }
525         break;
526
527     case '-':
528         if (isInfinity(data + 1, end)) {
529             data += SizeOfInfinity + 1;
530             return -std::numeric_limits<double>::infinity();
531         }
532         break;
533     }
534
535     // Not a number.
536     return PNaN;
537 }
538
539 template <typename CharType>
540 static double toDouble(const CharType* characters, unsigned size)
541 {
542     const CharType* endCharacters = characters + size;
543
544     // Skip leading white space.
545     for (; characters < endCharacters; ++characters) {
546         if (!isStrWhiteSpace(*characters))
547             break;
548     }
549     
550     // Empty string.
551     if (characters == endCharacters)
552         return 0.0;
553     
554     double number;
555     if (characters[0] == '0' && characters + 2 < endCharacters) {
556         if ((characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
557             number = jsHexIntegerLiteral(characters, endCharacters);
558         else if ((characters[1] | 0x20) == 'o' && isASCIIOctalDigit(characters[2]))
559             number = jsOctalIntegerLiteral(characters, endCharacters);
560         else if ((characters[1] | 0x20) == 'b' && isASCIIBinaryDigit(characters[2]))
561             number = jsBinaryIntegerLiteral(characters, endCharacters);
562         else
563             number = jsStrDecimalLiteral(characters, endCharacters);
564     } else
565         number = jsStrDecimalLiteral(characters, endCharacters);
566     
567     // Allow trailing white space.
568     for (; characters < endCharacters; ++characters) {
569         if (!isStrWhiteSpace(*characters))
570             break;
571     }
572     if (characters != endCharacters)
573         return PNaN;
574     
575     return number;
576 }
577
578 // See ecma-262 6th 11.8.3
579 double jsToNumber(StringView s)
580 {
581     unsigned size = s.length();
582
583     if (size == 1) {
584         UChar c = s[0];
585         if (isASCIIDigit(c))
586             return c - '0';
587         if (isStrWhiteSpace(c))
588             return 0;
589         return PNaN;
590     }
591
592     if (s.is8Bit())
593         return toDouble(s.characters8(), size);
594     return toDouble(s.characters16(), size);
595 }
596
597 static double parseFloat(StringView s)
598 {
599     unsigned size = s.length();
600
601     if (size == 1) {
602         UChar c = s[0];
603         if (isASCIIDigit(c))
604             return c - '0';
605         return PNaN;
606     }
607
608     if (s.is8Bit()) {
609         const LChar* data = s.characters8();
610         const LChar* end = data + size;
611
612         // Skip leading white space.
613         for (; data < end; ++data) {
614             if (!isStrWhiteSpace(*data))
615                 break;
616         }
617
618         // Empty string.
619         if (data == end)
620             return PNaN;
621
622         return jsStrDecimalLiteral(data, end);
623     }
624
625     const UChar* data = s.characters16();
626     const UChar* end = data + size;
627
628     // Skip leading white space.
629     for (; data < end; ++data) {
630         if (!isStrWhiteSpace(*data))
631             break;
632     }
633
634     // Empty string.
635     if (data == end)
636         return PNaN;
637
638     return jsStrDecimalLiteral(data, end);
639 }
640
641 EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
642 {
643     JSValue x = exec->argument(0);
644     if (!x.isString())
645         return JSValue::encode(x);
646
647     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
648     if (!globalObject->evalEnabled()) {
649         exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
650         return JSValue::encode(jsUndefined());
651     }
652
653     String s = x.toString(exec)->value(exec);
654     if (exec->hadException())
655         return JSValue::encode(jsUndefined());
656
657     if (s.is8Bit()) {
658         LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);
659         if (JSValue parsedObject = preparser.tryLiteralParse())
660             return JSValue::encode(parsedObject);
661     } else {
662         LiteralParser<UChar> preparser(exec, s.characters16(), s.length(), NonStrictJSON);
663         if (JSValue parsedObject = preparser.tryLiteralParse())
664             return JSValue::encode(parsedObject);        
665     }
666
667     JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject();
668     VariableEnvironment emptyTDZVariables; // Indirect eval does not have access to the lexical scope.
669     EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false, DerivedContextType::None, false, EvalContextType::None, &emptyTDZVariables);
670     if (!eval)
671         return JSValue::encode(jsUndefined());
672
673     return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject->globalScope()));
674 }
675
676 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
677 {
678     JSValue value = exec->argument(0);
679     JSValue radixValue = exec->argument(1);
680
681     // Optimized handling for numbers:
682     // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
683     // results in a truncation to integer. In the case of -0, this is converted to 0.
684     //
685     // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
686     // however these values cannot be trivially truncated to int since 10^21 exceeds
687     // even the int64_t range. Negative numbers are a little trickier, the case for
688     // values in the range -10^21 < n <= -1 are similar to those for integer, but
689     // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
690     static const double tenToTheMinus6 = 0.000001;
691     static const double intMaxPlusOne = 2147483648.0;
692     if (value.isNumber()) {
693         double n = value.asNumber();
694         if (((n < intMaxPlusOne && n >= tenToTheMinus6) || !n) && radixValue.isUndefinedOrNull())
695             return JSValue::encode(jsNumber(static_cast<int32_t>(n)));
696     }
697
698     // If ToString throws, we shouldn't call ToInt32.
699     return toSafeView(exec, value, [&] (JSString::SafeView& view) {
700         return JSValue::encode(jsNumber(parseInt(view.get(), radixValue.toInt32(exec))));
701     });
702 }
703
704 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
705 {
706     return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->view(exec).get())));
707 }
708
709 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
710 {
711     static Bitmap<256> doNotUnescapeWhenDecodingURI = makeCharacterBitmap(
712         "#$&+,/:;=?@"
713     );
714
715     return JSValue::encode(decode(exec, doNotUnescapeWhenDecodingURI, true));
716 }
717
718 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
719 {
720     static Bitmap<256> emptyBitmap;
721     return JSValue::encode(decode(exec, emptyBitmap, true));
722 }
723
724 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
725 {
726     static Bitmap<256> doNotEscapeWhenEncodingURI = makeCharacterBitmap(
727         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
728         "abcdefghijklmnopqrstuvwxyz"
729         "0123456789"
730         "!#$&'()*+,-./:;=?@_~"
731     );
732
733     return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURI));
734 }
735
736 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
737 {
738     static Bitmap<256> doNotEscapeWhenEncodingURIComponent = makeCharacterBitmap(
739         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
740         "abcdefghijklmnopqrstuvwxyz"
741         "0123456789"
742         "!'()*-._~"
743     );
744
745     return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURIComponent));
746 }
747
748 EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
749 {
750     static Bitmap<256> doNotEscape = makeCharacterBitmap(
751         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
752         "abcdefghijklmnopqrstuvwxyz"
753         "0123456789"
754         "*+-./@_"
755     );
756
757     return JSValue::encode(toSafeView(exec, exec->argument(0), [&] (JSString::SafeView& view) {
758         JSStringBuilder builder;
759         if (view.is8Bit()) {
760             const LChar* c = view.characters8();
761             for (unsigned k = 0; k < view.length(); k++, c++) {
762                 int u = c[0];
763                 if (doNotEscape.get(static_cast<LChar>(u)))
764                     builder.append(*c);
765                 else {
766                     builder.append(static_cast<LChar>('%'));
767                     appendByteAsHex(static_cast<LChar>(u), builder);
768                 }
769             }
770
771             return builder.build(exec);
772         }
773
774         const UChar* c = view.characters16();
775         for (unsigned k = 0; k < view.length(); k++, c++) {
776             UChar u = c[0];
777             if (u >= doNotEscape.size()) {
778                 builder.append(static_cast<LChar>('%'));
779                 builder.append(static_cast<LChar>('u'));
780                 appendByteAsHex(u >> 8, builder);
781                 appendByteAsHex(u & 0xFF, builder);
782             } else if (doNotEscape.get(static_cast<LChar>(u)))
783                 builder.append(*c);
784             else {
785                 builder.append(static_cast<LChar>('%'));
786                 appendByteAsHex(u, builder);
787             }
788         }
789
790         return builder.build(exec);
791     }));
792 }
793
794 EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
795 {
796     return JSValue::encode(toSafeView(exec, exec->argument(0), [&] (JSString::SafeView& view) {
797         StringBuilder builder;
798         int k = 0;
799         int len = view.length();
800
801         if (view.is8Bit()) {
802             const LChar* characters = view.characters8();
803             LChar convertedLChar;
804             while (k < len) {
805                 const LChar* c = characters + k;
806                 if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
807                     if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
808                         builder.append(Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]));
809                         k += 6;
810                         continue;
811                     }
812                 } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
813                     convertedLChar = LChar(Lexer<LChar>::convertHex(c[1], c[2]));
814                     c = &convertedLChar;
815                     k += 2;
816                 }
817                 builder.append(*c);
818                 k++;
819             }
820         } else {
821             const UChar* characters = view.characters16();
822
823             while (k < len) {
824                 const UChar* c = characters + k;
825                 UChar convertedUChar;
826                 if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
827                     if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
828                         convertedUChar = Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]);
829                         c = &convertedUChar;
830                         k += 5;
831                     }
832                 } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
833                     convertedUChar = UChar(Lexer<UChar>::convertHex(c[1], c[2]));
834                     c = &convertedUChar;
835                     k += 2;
836                 }
837                 k++;
838                 builder.append(*c);
839             }
840         }
841
842         return jsString(exec, builder.toString());
843     }));
844 }
845
846 EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState* exec)
847 {
848     return throwVMTypeError(exec);
849 }
850     
851 EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeErrorArgumentsCalleeAndCaller(ExecState* exec)
852 {
853     return throwVMTypeError(exec, "'arguments', 'callee', and 'caller' cannot be accessed in strict mode.");
854 }
855
856 class GlobalFuncProtoGetterFunctor {
857 public:
858     GlobalFuncProtoGetterFunctor(ExecState* exec, JSObject* thisObject)
859         : m_exec(exec)
860         , m_hasSkippedFirstFrame(false)
861         , m_thisObject(thisObject)
862         , m_result(JSValue::encode(jsUndefined()))
863     {
864     }
865
866     EncodedJSValue result() { return m_result; }
867
868     StackVisitor::Status operator()(StackVisitor& visitor) const
869     {
870         if (!m_hasSkippedFirstFrame) {
871             m_hasSkippedFirstFrame = true;
872             return StackVisitor::Continue;
873         }
874
875         if (m_thisObject->allowsAccessFrom(visitor->callFrame()))
876             m_result = JSValue::encode(m_thisObject->getPrototype(m_exec->vm(), m_exec));
877
878         return StackVisitor::Done;
879     }
880
881 private:
882     ExecState* m_exec;
883     mutable bool m_hasSkippedFirstFrame;
884     JSObject* m_thisObject;
885     mutable EncodedJSValue m_result;
886 };
887
888 EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
889 {
890     if (exec->thisValue().isUndefinedOrNull()) 
891         return throwVMError(exec, createTypeError(exec, "Can't convert undefined or null to object"));
892
893     JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
894
895     if (!thisObject) {
896         JSObject* prototype = exec->thisValue().synthesizePrototype(exec);
897         if (UNLIKELY(!prototype))
898             return JSValue::encode(JSValue());
899         return JSValue::encode(prototype);
900     }
901
902     GlobalFuncProtoGetterFunctor functor(exec, thisObject);
903     // This can throw but it's just unneeded extra work to check for it. The return
904     // value from this function is only used as the return value from a host call.
905     // Therefore, the return value is only used if there wasn't an exception.
906     exec->iterate(functor);
907     return functor.result();
908 }
909
910 class GlobalFuncProtoSetterFunctor {
911 public:
912     GlobalFuncProtoSetterFunctor(JSObject* thisObject)
913         : m_hasSkippedFirstFrame(false)
914         , m_allowsAccess(false)
915         , m_thisObject(thisObject)
916     {
917     }
918
919     bool allowsAccess() const { return m_allowsAccess; }
920
921     StackVisitor::Status operator()(StackVisitor& visitor) const
922     {
923         if (!m_hasSkippedFirstFrame) {
924             m_hasSkippedFirstFrame = true;
925             return StackVisitor::Continue;
926         }
927
928         m_allowsAccess = m_thisObject->allowsAccessFrom(visitor->callFrame());
929         return StackVisitor::Done;
930     }
931
932 private:
933     mutable bool m_hasSkippedFirstFrame;
934     mutable bool m_allowsAccess;
935     JSObject* m_thisObject;
936 };
937
938 bool checkProtoSetterAccessAllowed(ExecState* exec, JSObject* object)
939 {
940     GlobalFuncProtoSetterFunctor functor(object);
941     exec->iterate(functor);
942     return functor.allowsAccess();
943 }
944
945 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
946 {
947     if (exec->thisValue().isUndefinedOrNull()) 
948         return throwVMError(exec, createTypeError(exec, "Can't convert undefined or null to object"));
949
950     JSValue value = exec->argument(0);
951
952     JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
953
954     // Setting __proto__ of a primitive should have no effect.
955     if (!thisObject)
956         return JSValue::encode(jsUndefined());
957
958     if (!checkProtoSetterAccessAllowed(exec, thisObject))
959         return JSValue::encode(jsUndefined());
960
961     // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
962     if (!value.isObject() && !value.isNull())
963         return JSValue::encode(jsUndefined());
964
965     VM& vm = exec->vm();
966     bool shouldThrowIfCantSet = true;
967     thisObject->setPrototype(vm, exec, value, shouldThrowIfCantSet);
968     return JSValue::encode(jsUndefined());
969 }
970     
971 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState* exec)
972 {
973     dataLog(exec->argument(0).toWTFString(exec), "\n");
974     return JSValue::encode(jsUndefined());
975 }
976
977 } // namespace JSC