Rewrite Function.bind as a builtin
[WebKit.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 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 "GetterSetter.h"
30 #include "Interpreter.h"
31 #include "JSFunction.h"
32 #include "JSGlobalObject.h"
33 #include "JSString.h"
34 #include "JSStringBuilder.h"
35 #include "Lexer.h"
36 #include "LiteralParser.h"
37 #include "Nodes.h"
38 #include "JSCInlines.h"
39 #include "Parser.h"
40 #include "StackVisitor.h"
41 #include <wtf/dtoa.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <wtf/ASCIICType.h>
45 #include <wtf/Assertions.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 static JSValue encode(ExecState* exec, const char* doNotEscape)
57 {
58     CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(StrictConversion);
59     if (!cstr.data())
60         return exec->vm().throwException(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
61
62     JSStringBuilder builder;
63     const char* p = cstr.data();
64     for (size_t k = 0; k < cstr.length(); k++, p++) {
65         char c = *p;
66         if (c && strchr(doNotEscape, c))
67             builder.append(static_cast<LChar>(c));
68         else {
69             char tmp[4];
70             snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c));
71             builder.append(tmp);
72         }
73     }
74     return builder.build(exec);
75 }
76
77 template <typename CharType>
78 ALWAYS_INLINE
79 static JSValue decode(ExecState* exec, const CharType* characters, int length, const char* doNotUnescape, bool strict)
80 {
81     JSStringBuilder builder;
82     int k = 0;
83     UChar u = 0;
84     while (k < length) {
85         const CharType* p = characters + k;
86         CharType c = *p;
87         if (c == '%') {
88             int charLen = 0;
89             if (k <= length - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
90                 const char b0 = Lexer<CharType>::convertHex(p[1], p[2]);
91                 const int sequenceLen = UTF8SequenceLength(b0);
92                 if (sequenceLen && k <= length - sequenceLen * 3) {
93                     charLen = sequenceLen * 3;
94                     char sequence[5];
95                     sequence[0] = b0;
96                     for (int i = 1; i < sequenceLen; ++i) {
97                         const CharType* q = p + i * 3;
98                         if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
99                             sequence[i] = Lexer<CharType>::convertHex(q[1], q[2]);
100                         else {
101                             charLen = 0;
102                             break;
103                         }
104                     }
105                     if (charLen != 0) {
106                         sequence[sequenceLen] = 0;
107                         const int character = decodeUTF8Sequence(sequence);
108                         if (character < 0 || character >= 0x110000)
109                             charLen = 0;
110                         else if (character >= 0x10000) {
111                             // Convert to surrogate pair.
112                             builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
113                             u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
114                         } else
115                             u = static_cast<UChar>(character);
116                     }
117                 }
118             }
119             if (charLen == 0) {
120                 if (strict)
121                     return exec->vm().throwException(exec, createURIError(exec, ASCIILiteral("URI error")));
122                 // The only case where we don't use "strict" mode is the "unescape" function.
123                 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
124                 if (k <= length - 6 && p[1] == 'u'
125                         && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
126                         && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
127                     charLen = 6;
128                     u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
129                 }
130             }
131             if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
132                 builder.append(u);
133                 k += charLen;
134                 continue;
135             }
136         }
137         k++;
138         builder.append(c);
139     }
140     return builder.build(exec);
141 }
142
143 static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
144 {
145     String str = exec->argument(0).toString(exec)->value(exec);
146     
147     if (str.is8Bit())
148         return decode(exec, str.characters8(), str.length(), doNotUnescape, strict);
149     return decode(exec, str.characters16(), str.length(), doNotUnescape, strict);
150 }
151
152 bool isStrWhiteSpace(UChar c)
153 {
154     switch (c) {
155         // ECMA-262-5th 7.2 & 7.3
156         case 0x0009:
157         case 0x000A:
158         case 0x000B:
159         case 0x000C:
160         case 0x000D:
161         case 0x0020:
162         case 0x00A0:
163         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.
164         case 0x2028:
165         case 0x2029:
166         case 0xFEFF:
167             return true;
168         default:
169             return c > 0xFF && u_charType(c) == U_SPACE_SEPARATOR;
170     }
171 }
172
173 static int parseDigit(unsigned short c, int radix)
174 {
175     int digit = -1;
176
177     if (c >= '0' && c <= '9')
178         digit = c - '0';
179     else if (c >= 'A' && c <= 'Z')
180         digit = c - 'A' + 10;
181     else if (c >= 'a' && c <= 'z')
182         digit = c - 'a' + 10;
183
184     if (digit >= radix)
185         return -1;
186     return digit;
187 }
188
189 double parseIntOverflow(const LChar* s, unsigned length, int radix)
190 {
191     double number = 0.0;
192     double radixMultiplier = 1.0;
193
194     for (const LChar* p = s + length - 1; p >= s; p--) {
195         if (radixMultiplier == std::numeric_limits<double>::infinity()) {
196             if (*p != '0') {
197                 number = std::numeric_limits<double>::infinity();
198                 break;
199             }
200         } else {
201             int digit = parseDigit(*p, radix);
202             number += digit * radixMultiplier;
203         }
204
205         radixMultiplier *= radix;
206     }
207
208     return number;
209 }
210
211 static double parseIntOverflow(const UChar* s, unsigned length, int radix)
212 {
213     double number = 0.0;
214     double radixMultiplier = 1.0;
215
216     for (const UChar* p = s + length - 1; p >= s; p--) {
217         if (radixMultiplier == std::numeric_limits<double>::infinity()) {
218             if (*p != '0') {
219                 number = std::numeric_limits<double>::infinity();
220                 break;
221             }
222         } else {
223             int digit = parseDigit(*p, radix);
224             number += digit * radixMultiplier;
225         }
226
227         radixMultiplier *= radix;
228     }
229
230     return number;
231 }
232
233 static double parseIntOverflow(StringView string, int radix)
234 {
235     if (string.is8Bit())
236         return parseIntOverflow(string.characters8(), string.length(), radix);
237     return parseIntOverflow(string.characters16(), string.length(), radix);
238 }
239
240 // ES5.1 15.1.2.2
241 template <typename CharType>
242 ALWAYS_INLINE
243 static double parseInt(const String& s, const CharType* data, int radix)
244 {
245     // 1. Let inputString be ToString(string).
246     // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
247     //    StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
248     //    space.) If inputString does not contain any such characters, let S be the empty string.
249     int length = s.length();
250     int p = 0;
251     while (p < length && isStrWhiteSpace(data[p]))
252         ++p;
253
254     // 3. Let sign be 1.
255     // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
256     // 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.
257     double sign = 1;
258     if (p < length) {
259         if (data[p] == '+')
260             ++p;
261         else if (data[p] == '-') {
262             sign = -1;
263             ++p;
264         }
265     }
266
267     // 6. Let R = ToInt32(radix).
268     // 7. Let stripPrefix be true.
269     // 8. If R != 0,then
270     //   b. If R != 16, let stripPrefix be false.
271     // 9. Else, R == 0
272     //   a. LetR = 10.
273     // 10. If stripPrefix is true, then
274     //   a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
275     //      then remove the first two characters from S and let R = 16.
276     // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
277     //     consisting of all characters before the first such character; otherwise, let Z be S.
278     if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
279         radix = 16;
280         p += 2;
281     } else if (radix == 0)
282         radix = 10;
283
284     // 8.a If R < 2 or R > 36, then return NaN.
285     if (radix < 2 || radix > 36)
286         return QNaN;
287
288     // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
289     //     A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
290     //     digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
291     //     and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
292     //     mathematical integer value that is represented by Z in radix-R notation.)
293     // 14. Let number be the Number value for mathInt.
294     int firstDigitPosition = p;
295     bool sawDigit = false;
296     double number = 0;
297     while (p < length) {
298         int digit = parseDigit(data[p], radix);
299         if (digit == -1)
300             break;
301         sawDigit = true;
302         number *= radix;
303         number += digit;
304         ++p;
305     }
306
307     // 12. If Z is empty, return NaN.
308     if (!sawDigit)
309         return QNaN;
310
311     // Alternate code path for certain large numbers.
312     if (number >= mantissaOverflowLowerBound) {
313         if (radix == 10) {
314             size_t parsedLength;
315             number = parseDouble(StringView(s).substring(firstDigitPosition, p - firstDigitPosition), parsedLength);
316         } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
317             number = parseIntOverflow(StringView(s).substring(firstDigitPosition, p - firstDigitPosition), radix);
318     }
319
320     // 15. Return sign x number.
321     return sign * number;
322 }
323
324 static double parseInt(const String& s, int radix)
325 {
326     if (s.is8Bit())
327         return parseInt(s, s.characters8(), radix);
328     return parseInt(s, s.characters16(), radix);
329 }
330
331 static const int SizeOfInfinity = 8;
332
333 template <typename CharType>
334 static bool isInfinity(const CharType* data, const CharType* end)
335 {
336     return (end - data) >= SizeOfInfinity
337         && data[0] == 'I'
338         && data[1] == 'n'
339         && data[2] == 'f'
340         && data[3] == 'i'
341         && data[4] == 'n'
342         && data[5] == 'i'
343         && data[6] == 't'
344         && data[7] == 'y';
345 }
346
347 // See ecma-262 9.3.1
348 template <typename CharType>
349 static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
350 {
351     // Hex number.
352     data += 2;
353     const CharType* firstDigitPosition = data;
354     double number = 0;
355     while (true) {
356         number = number * 16 + toASCIIHexValue(*data);
357         ++data;
358         if (data == end)
359             break;
360         if (!isASCIIHexDigit(*data))
361             break;
362     }
363     if (number >= mantissaOverflowLowerBound)
364         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
365
366     return number;
367 }
368
369 // See ecma-262 9.3.1
370 template <typename CharType>
371 static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
372 {
373     RELEASE_ASSERT(data < end);
374
375     size_t parsedLength;
376     double number = parseDouble(data, end - data, parsedLength);
377     if (parsedLength) {
378         data += parsedLength;
379         return number;
380     }
381
382     // Check for [+-]?Infinity
383     switch (*data) {
384     case 'I':
385         if (isInfinity(data, end)) {
386             data += SizeOfInfinity;
387             return std::numeric_limits<double>::infinity();
388         }
389         break;
390
391     case '+':
392         if (isInfinity(data + 1, end)) {
393             data += SizeOfInfinity + 1;
394             return std::numeric_limits<double>::infinity();
395         }
396         break;
397
398     case '-':
399         if (isInfinity(data + 1, end)) {
400             data += SizeOfInfinity + 1;
401             return -std::numeric_limits<double>::infinity();
402         }
403         break;
404     }
405
406     // Not a number.
407     return QNaN;
408 }
409
410 template <typename CharType>
411 static double toDouble(const CharType* characters, unsigned size)
412 {
413     const CharType* endCharacters = characters + size;
414
415     // Skip leading white space.
416     for (; characters < endCharacters; ++characters) {
417         if (!isStrWhiteSpace(*characters))
418             break;
419     }
420     
421     // Empty string.
422     if (characters == endCharacters)
423         return 0.0;
424     
425     double number;
426     if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
427         number = jsHexIntegerLiteral(characters, endCharacters);
428     else
429         number = jsStrDecimalLiteral(characters, endCharacters);
430     
431     // Allow trailing white space.
432     for (; characters < endCharacters; ++characters) {
433         if (!isStrWhiteSpace(*characters))
434             break;
435     }
436     if (characters != endCharacters)
437         return QNaN;
438     
439     return number;
440 }
441
442 // See ecma-262 9.3.1
443 double jsToNumber(const String& s)
444 {
445     unsigned size = s.length();
446
447     if (size == 1) {
448         UChar c = s[0];
449         if (isASCIIDigit(c))
450             return c - '0';
451         if (isStrWhiteSpace(c))
452             return 0;
453         return QNaN;
454     }
455
456     if (s.is8Bit())
457         return toDouble(s.characters8(), size);
458     return toDouble(s.characters16(), size);
459 }
460
461 static double parseFloat(const String& s)
462 {
463     unsigned size = s.length();
464
465     if (size == 1) {
466         UChar c = s[0];
467         if (isASCIIDigit(c))
468             return c - '0';
469         return QNaN;
470     }
471
472     if (s.is8Bit()) {
473         const LChar* data = s.characters8();
474         const LChar* end = data + size;
475
476         // Skip leading white space.
477         for (; data < end; ++data) {
478             if (!isStrWhiteSpace(*data))
479                 break;
480         }
481
482         // Empty string.
483         if (data == end)
484             return QNaN;
485
486         return jsStrDecimalLiteral(data, end);
487     }
488
489     const UChar* data = s.characters16();
490     const UChar* end = data + size;
491
492     // Skip leading white space.
493     for (; data < end; ++data) {
494         if (!isStrWhiteSpace(*data))
495             break;
496     }
497
498     // Empty string.
499     if (data == end)
500         return QNaN;
501
502     return jsStrDecimalLiteral(data, end);
503 }
504
505 EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
506 {
507     JSValue x = exec->argument(0);
508     if (!x.isString())
509         return JSValue::encode(x);
510
511     String s = x.toString(exec)->value(exec);
512
513     if (s.is8Bit()) {
514         LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);
515         if (JSValue parsedObject = preparser.tryLiteralParse())
516             return JSValue::encode(parsedObject);
517     } else {
518         LiteralParser<UChar> preparser(exec, s.characters16(), s.length(), NonStrictJSON);
519         if (JSValue parsedObject = preparser.tryLiteralParse())
520             return JSValue::encode(parsedObject);        
521     }
522
523     JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject();
524     EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
525     if (!eval)
526         return JSValue::encode(jsUndefined());
527
528     return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject));
529 }
530
531 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
532 {
533     JSValue value = exec->argument(0);
534     JSValue radixValue = exec->argument(1);
535
536     // Optimized handling for numbers:
537     // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
538     // results in a truncation to integer. In the case of -0, this is converted to 0.
539     //
540     // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
541     // however these values cannot be trivially truncated to int since 10^21 exceeds
542     // even the int64_t range. Negative numbers are a little trickier, the case for
543     // values in the range -10^21 < n <= -1 are similar to those for integer, but
544     // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
545     static const double tenToTheMinus6 = 0.000001;
546     static const double intMaxPlusOne = 2147483648.0;
547     if (value.isNumber()) {
548         double n = value.asNumber();
549         if (((n < intMaxPlusOne && n >= tenToTheMinus6) || !n) && radixValue.isUndefinedOrNull())
550             return JSValue::encode(jsNumber(static_cast<int32_t>(n)));
551     }
552
553     // If ToString throws, we shouldn't call ToInt32.
554     String s = value.toString(exec)->value(exec);
555     if (exec->hadException())
556         return JSValue::encode(jsUndefined());
557
558     return JSValue::encode(jsNumber(parseInt(s, radixValue.toInt32(exec))));
559 }
560
561 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
562 {
563     return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->value(exec))));
564 }
565
566 EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
567 {
568     return JSValue::encode(jsBoolean(std::isnan(exec->argument(0).toNumber(exec))));
569 }
570
571 EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
572 {
573     double n = exec->argument(0).toNumber(exec);
574     return JSValue::encode(jsBoolean(std::isfinite(n)));
575 }
576
577 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
578 {
579     static const char do_not_unescape_when_decoding_URI[] =
580         "#$&+,/:;=?@";
581
582     return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
583 }
584
585 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
586 {
587     return JSValue::encode(decode(exec, "", true));
588 }
589
590 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
591 {
592     static const char do_not_escape_when_encoding_URI[] =
593         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
594         "abcdefghijklmnopqrstuvwxyz"
595         "0123456789"
596         "!#$&'()*+,-./:;=?@_~";
597
598     return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
599 }
600
601 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
602 {
603     static const char do_not_escape_when_encoding_URI_component[] =
604         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
605         "abcdefghijklmnopqrstuvwxyz"
606         "0123456789"
607         "!'()*-._~";
608
609     return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
610 }
611
612 EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
613 {
614     static const char do_not_escape[] =
615         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
616         "abcdefghijklmnopqrstuvwxyz"
617         "0123456789"
618         "*+-./@_";
619
620     JSStringBuilder builder;
621     String str = exec->argument(0).toString(exec)->value(exec);
622     if (str.is8Bit()) {
623         const LChar* c = str.characters8();
624         for (unsigned k = 0; k < str.length(); k++, c++) {
625             int u = c[0];
626             if (u && strchr(do_not_escape, static_cast<char>(u)))
627                 builder.append(*c);
628             else {
629                 char tmp[4];
630                 snprintf(tmp, sizeof(tmp), "%%%02X", u);
631                 builder.append(tmp);
632             }
633         }
634
635         return JSValue::encode(builder.build(exec));        
636     }
637
638     const UChar* c = str.characters16();
639     for (unsigned k = 0; k < str.length(); k++, c++) {
640         int u = c[0];
641         if (u > 255) {
642             char tmp[7];
643             snprintf(tmp, sizeof(tmp), "%%u%04X", u);
644             builder.append(tmp);
645         } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
646             builder.append(*c);
647         else {
648             char tmp[4];
649             snprintf(tmp, sizeof(tmp), "%%%02X", u);
650             builder.append(tmp);
651         }
652     }
653
654     return JSValue::encode(builder.build(exec));
655 }
656
657 EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
658 {
659     StringBuilder builder;
660     String str = exec->argument(0).toString(exec)->value(exec);
661     int k = 0;
662     int len = str.length();
663     
664     if (str.is8Bit()) {
665         const LChar* characters = str.characters8();
666         LChar convertedLChar;
667         while (k < len) {
668             const LChar* c = characters + k;
669             if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
670                 if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
671                     builder.append(Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]));
672                     k += 6;
673                     continue;
674                 }
675             } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
676                 convertedLChar = LChar(Lexer<LChar>::convertHex(c[1], c[2]));
677                 c = &convertedLChar;
678                 k += 2;
679             }
680             builder.append(*c);
681             k++;
682         }        
683     } else {
684         const UChar* characters = str.characters16();
685
686         while (k < len) {
687             const UChar* c = characters + k;
688             UChar convertedUChar;
689             if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
690                 if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
691                     convertedUChar = Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]);
692                     c = &convertedUChar;
693                     k += 5;
694                 }
695             } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
696                 convertedUChar = UChar(Lexer<UChar>::convertHex(c[1], c[2]));
697                 c = &convertedUChar;
698                 k += 2;
699             }
700             k++;
701             builder.append(*c);
702         }
703     }
704
705     return JSValue::encode(jsString(exec, builder.toString()));
706 }
707
708 EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState* exec)
709 {
710     return throwVMTypeError(exec);
711 }
712
713 class GlobalFuncProtoGetterFunctor {
714 public:
715     GlobalFuncProtoGetterFunctor(JSObject* thisObject)
716         : m_hasSkippedFirstFrame(false)
717         , m_thisObject(thisObject)
718         , m_result(JSValue::encode(jsUndefined()))
719     {
720     }
721
722     EncodedJSValue result() { return m_result; }
723
724     StackVisitor::Status operator()(StackVisitor& visitor)
725     {
726         if (!m_hasSkippedFirstFrame) {
727             m_hasSkippedFirstFrame = true;
728             return StackVisitor::Continue;
729         }
730
731         if (m_thisObject->allowsAccessFrom(visitor->callFrame()))
732             m_result = JSValue::encode(m_thisObject->prototype());
733
734         return StackVisitor::Done;
735     }
736
737 private:
738     bool m_hasSkippedFirstFrame;
739     JSObject* m_thisObject;
740     EncodedJSValue m_result;
741 };
742
743 EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
744 {
745     JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
746
747     if (!thisObject)
748         return JSValue::encode(exec->thisValue().synthesizePrototype(exec));
749
750     GlobalFuncProtoGetterFunctor functor(thisObject);
751     exec->iterate(functor);
752     return functor.result();
753 }
754
755 class GlobalFuncProtoSetterFunctor {
756 public:
757     GlobalFuncProtoSetterFunctor(JSObject* thisObject)
758         : m_hasSkippedFirstFrame(false)
759         , m_allowsAccess(false)
760         , m_thisObject(thisObject)
761     {
762     }
763
764     bool allowsAccess() const { return m_allowsAccess; }
765
766     StackVisitor::Status operator()(StackVisitor& visitor)
767     {
768         if (!m_hasSkippedFirstFrame) {
769             m_hasSkippedFirstFrame = true;
770             return StackVisitor::Continue;
771         }
772
773         m_allowsAccess = m_thisObject->allowsAccessFrom(visitor->callFrame());
774         return StackVisitor::Done;
775     }
776
777 private:
778     bool m_hasSkippedFirstFrame;
779     bool m_allowsAccess;
780     JSObject* m_thisObject;
781 };
782
783 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
784 {
785     JSValue value = exec->argument(0);
786
787     JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
788
789     // Setting __proto__ of a primitive should have no effect.
790     if (!thisObject)
791         return JSValue::encode(jsUndefined());
792
793     GlobalFuncProtoSetterFunctor functor(thisObject);
794     exec->iterate(functor);
795     if (!functor.allowsAccess())
796         return JSValue::encode(jsUndefined());
797
798     // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
799     if (!value.isObject() && !value.isNull())
800         return JSValue::encode(jsUndefined());
801
802     if (!thisObject->isExtensible())
803         return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
804
805     if (!thisObject->setPrototypeWithCycleCheck(exec, value))
806         exec->vm().throwException(exec, createError(exec, "cyclic __proto__ value"));
807     return JSValue::encode(jsUndefined());
808 }
809     
810 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState* exec)
811 {
812     dataLog(exec->argument(0).toWTFString(exec), "\n");
813     return JSValue::encode(jsUndefined());
814 }
815
816     
817 EncodedJSValue JSC_HOST_CALL globalFuncSetTypeErrorAccessor(ExecState* exec)
818 {
819     JSObject* target = jsDynamicCast<JSObject*>(exec->argument(0));
820     JSValue propertyName = exec->argument(1);
821     
822     // Setting __proto__ of a primitive should have no effect.
823     if (!target || !propertyName.isString())
824         return JSValue::encode(jsUndefined());
825     VM& vm = exec->vm();
826     Identifier property(exec, asString(propertyName)->getString(exec));
827     target->putDirectNonIndexAccessor(vm, vm.propertyNames->arguments, target->globalObject()->throwTypeErrorGetterSetter(vm), DontDelete | DontEnum | Accessor);
828     return JSValue::encode(jsUndefined());
829 }
830     
831 } // namespace JSC