[JSC] Drop direct references to Intl constructors by rewriting Intl JS builtins in C++
[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-2018 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 "CatchScope.h"
30 #include "EvalExecutable.h"
31 #include "Exception.h"
32 #include "IndirectEvalExecutable.h"
33 #include "Interpreter.h"
34 #include "IntlDateTimeFormat.h"
35 #include "IntlObject.h"
36 #include "JSCInlines.h"
37 #include "JSFunction.h"
38 #include "JSGlobalObject.h"
39 #include "JSInternalPromise.h"
40 #include "JSModuleLoader.h"
41 #include "JSPromise.h"
42 #include "JSPromiseDeferred.h"
43 #include "JSString.h"
44 #include "Lexer.h"
45 #include "LiteralParser.h"
46 #include "Nodes.h"
47 #include "JSCInlines.h"
48 #include "ParseInt.h"
49 #include "Parser.h"
50 #include "StackVisitor.h"
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <unicode/utf8.h>
54 #include <wtf/ASCIICType.h>
55 #include <wtf/Assertions.h>
56 #include <wtf/HexNumber.h>
57 #include <wtf/MathExtras.h>
58 #include <wtf/dtoa.h>
59 #include <wtf/text/StringBuilder.h>
60 #include <wtf/unicode/UTF8Conversion.h>
61
62 namespace JSC {
63
64 using namespace WTF::Unicode;
65
66 const ASCIILiteral ObjectProtoCalledOnNullOrUndefinedError { "Object.prototype.__proto__ called on null or undefined"_s };
67
68 template<unsigned charactersCount>
69 static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount])
70 {
71     static_assert(charactersCount > 0, "Since string literal is null terminated, characterCount is always larger than 0");
72     Bitmap<256> bitmap;
73     for (unsigned i = 0; i < charactersCount - 1; ++i)
74         bitmap.set(characters[i]);
75     return bitmap;
76 }
77
78 template<typename CharacterType>
79 static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape, const CharacterType* characters, unsigned length)
80 {
81     VM& vm = exec->vm();
82     auto scope = DECLARE_THROW_SCOPE(vm);
83
84     // 18.2.6.1.1 Runtime Semantics: Encode ( string, unescapedSet )
85     // https://tc39.github.io/ecma262/#sec-encode
86
87     auto throwException = [&scope, exec] {
88         return JSC::throwException(exec, scope, createURIError(exec, "String contained an illegal UTF-16 sequence."_s));
89     };
90
91     StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
92     builder.reserveCapacity(length);
93
94     // 4. Repeat
95     auto* end = characters + length;
96     for (auto* cursor = characters; cursor != end; ++cursor) {
97         auto character = *cursor;
98
99         // 4-c. If C is in unescapedSet, then
100         if (character < doNotEscape.size() && doNotEscape.get(character)) {
101             // 4-c-i. Let S be a String containing only the code unit C.
102             // 4-c-ii. Let R be a new String value computed by concatenating the previous value of R and S.
103             builder.append(static_cast<LChar>(character));
104             continue;
105         }
106
107         // 4-d-i. If the code unit value of C is not less than 0xDC00 and not greater than 0xDFFF, throw a URIError exception.
108         if (U16_IS_TRAIL(character))
109             return throwException();
110
111         // 4-d-ii. If the code unit value of C is less than 0xD800 or greater than 0xDBFF, then
112         // 4-d-ii-1. Let V be the code unit value of C.
113         UChar32 codePoint;
114         if (!U16_IS_LEAD(character))
115             codePoint = character;
116         else {
117             // 4-d-iii. Else,
118             // 4-d-iii-1. Increase k by 1.
119             ++cursor;
120
121             // 4-d-iii-2. If k equals strLen, throw a URIError exception.
122             if (cursor == end)
123                 return throwException();
124
125             // 4-d-iii-3. Let kChar be the code unit value of the code unit at index k within string.
126             auto trail = *cursor;
127
128             // 4-d-iii-4. If kChar is less than 0xDC00 or greater than 0xDFFF, throw a URIError exception.
129             if (!U16_IS_TRAIL(trail))
130                 return throwException();
131
132             // 4-d-iii-5. Let V be UTF16Decode(C, kChar).
133             codePoint = U16_GET_SUPPLEMENTARY(character, trail);
134         }
135
136         // 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.
137         LChar utf8OctetsBuffer[U8_MAX_LENGTH];
138         unsigned utf8Length = 0;
139         // We can use U8_APPEND_UNSAFE here since codePoint is either
140         // 1. non surrogate one, correct code point.
141         // 2. correct code point generated from validated lead and trail surrogates.
142         U8_APPEND_UNSAFE(utf8OctetsBuffer, utf8Length, codePoint);
143
144         // 4-d-v. Let j be 0.
145         // 4-d-vi. Repeat, while j < L
146         for (unsigned index = 0; index < utf8Length; ++index) {
147             // 4-d-vi-1. Let jOctet be the value at index j within Octets.
148             // 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.
149             // 4-d-vi-3. Let R be a new String value computed by concatenating the previous value of R and S.
150             builder.append('%');
151             appendByteAsHex(utf8OctetsBuffer[index], builder);
152         }
153     }
154
155     if (UNLIKELY(builder.hasOverflowed()))
156         return throwOutOfMemoryError(exec, scope);
157     return jsString(exec, builder.toString());
158 }
159
160 static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape)
161 {
162     return toStringView(exec, exec->argument(0), [&] (StringView view) {
163         if (view.is8Bit())
164             return encode(exec, doNotEscape, view.characters8(), view.length());
165         return encode(exec, doNotEscape, view.characters16(), view.length());
166     });
167 }
168
169 template <typename CharType>
170 ALWAYS_INLINE
171 static JSValue decode(ExecState* exec, const CharType* characters, int length, const Bitmap<256>& doNotUnescape, bool strict)
172 {
173     VM& vm = exec->vm();
174     auto scope = DECLARE_THROW_SCOPE(vm);
175
176     StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
177     int k = 0;
178     UChar u = 0;
179     while (k < length) {
180         const CharType* p = characters + k;
181         CharType c = *p;
182         if (c == '%') {
183             int charLen = 0;
184             if (k <= length - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
185                 const char b0 = Lexer<CharType>::convertHex(p[1], p[2]);
186                 const int sequenceLen = UTF8SequenceLength(b0);
187                 if (sequenceLen && k <= length - sequenceLen * 3) {
188                     charLen = sequenceLen * 3;
189                     char sequence[5];
190                     sequence[0] = b0;
191                     for (int i = 1; i < sequenceLen; ++i) {
192                         const CharType* q = p + i * 3;
193                         if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
194                             sequence[i] = Lexer<CharType>::convertHex(q[1], q[2]);
195                         else {
196                             charLen = 0;
197                             break;
198                         }
199                     }
200                     if (charLen != 0) {
201                         sequence[sequenceLen] = 0;
202                         const int character = decodeUTF8Sequence(sequence);
203                         if (character < 0 || character >= 0x110000)
204                             charLen = 0;
205                         else if (character >= 0x10000) {
206                             // Convert to surrogate pair.
207                             builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
208                             u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
209                         } else
210                             u = static_cast<UChar>(character);
211                     }
212                 }
213             }
214             if (charLen == 0) {
215                 if (strict)
216                     return throwException(exec, scope, createURIError(exec, "URI error"_s));
217                 // The only case where we don't use "strict" mode is the "unescape" function.
218                 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
219                 if (k <= length - 6 && p[1] == 'u'
220                         && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
221                         && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
222                     charLen = 6;
223                     u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
224                 }
225             }
226             if (charLen && (u >= 128 || !doNotUnescape.get(static_cast<LChar>(u)))) {
227                 builder.append(u);
228                 k += charLen;
229                 continue;
230             }
231         }
232         k++;
233         builder.append(c);
234     }
235     if (UNLIKELY(builder.hasOverflowed()))
236         return throwOutOfMemoryError(exec, scope);
237     RELEASE_AND_RETURN(scope, jsString(&vm, builder.toString()));
238 }
239
240 static JSValue decode(ExecState* exec, const Bitmap<256>& doNotUnescape, bool strict)
241 {
242     return toStringView(exec, exec->argument(0), [&] (StringView view) {
243         if (view.is8Bit())
244             return decode(exec, view.characters8(), view.length(), doNotUnescape, strict);
245         return decode(exec, view.characters16(), view.length(), doNotUnescape, strict);
246     });
247 }
248
249 static const int SizeOfInfinity = 8;
250
251 template <typename CharType>
252 static bool isInfinity(const CharType* data, const CharType* end)
253 {
254     return (end - data) >= SizeOfInfinity
255         && data[0] == 'I'
256         && data[1] == 'n'
257         && data[2] == 'f'
258         && data[3] == 'i'
259         && data[4] == 'n'
260         && data[5] == 'i'
261         && data[6] == 't'
262         && data[7] == 'y';
263 }
264
265 // See ecma-262 6th 11.8.3
266 template <typename CharType>
267 static double jsBinaryIntegerLiteral(const CharType*& data, const CharType* end)
268 {
269     // Binary number.
270     data += 2;
271     const CharType* firstDigitPosition = data;
272     double number = 0;
273     while (true) {
274         number = number * 2 + (*data - '0');
275         ++data;
276         if (data == end)
277             break;
278         if (!isASCIIBinaryDigit(*data))
279             break;
280     }
281     if (number >= mantissaOverflowLowerBound)
282         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 2);
283
284     return number;
285 }
286
287 // See ecma-262 6th 11.8.3
288 template <typename CharType>
289 static double jsOctalIntegerLiteral(const CharType*& data, const CharType* end)
290 {
291     // Octal number.
292     data += 2;
293     const CharType* firstDigitPosition = data;
294     double number = 0;
295     while (true) {
296         number = number * 8 + (*data - '0');
297         ++data;
298         if (data == end)
299             break;
300         if (!isASCIIOctalDigit(*data))
301             break;
302     }
303     if (number >= mantissaOverflowLowerBound)
304         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 8);
305
306     return number;
307 }
308
309 // See ecma-262 6th 11.8.3
310 template <typename CharType>
311 static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
312 {
313     // Hex number.
314     data += 2;
315     const CharType* firstDigitPosition = data;
316     double number = 0;
317     while (true) {
318         number = number * 16 + toASCIIHexValue(*data);
319         ++data;
320         if (data == end)
321             break;
322         if (!isASCIIHexDigit(*data))
323             break;
324     }
325     if (number >= mantissaOverflowLowerBound)
326         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
327
328     return number;
329 }
330
331 // See ecma-262 6th 11.8.3
332 template <typename CharType>
333 static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
334 {
335     RELEASE_ASSERT(data < end);
336
337     size_t parsedLength;
338     double number = parseDouble(data, end - data, parsedLength);
339     if (parsedLength) {
340         data += parsedLength;
341         return number;
342     }
343
344     // Check for [+-]?Infinity
345     switch (*data) {
346     case 'I':
347         if (isInfinity(data, end)) {
348             data += SizeOfInfinity;
349             return std::numeric_limits<double>::infinity();
350         }
351         break;
352
353     case '+':
354         if (isInfinity(data + 1, end)) {
355             data += SizeOfInfinity + 1;
356             return std::numeric_limits<double>::infinity();
357         }
358         break;
359
360     case '-':
361         if (isInfinity(data + 1, end)) {
362             data += SizeOfInfinity + 1;
363             return -std::numeric_limits<double>::infinity();
364         }
365         break;
366     }
367
368     // Not a number.
369     return PNaN;
370 }
371
372 template <typename CharType>
373 static double toDouble(const CharType* characters, unsigned size)
374 {
375     const CharType* endCharacters = characters + size;
376
377     // Skip leading white space.
378     for (; characters < endCharacters; ++characters) {
379         if (!isStrWhiteSpace(*characters))
380             break;
381     }
382
383     // Empty string.
384     if (characters == endCharacters)
385         return 0.0;
386
387     double number;
388     if (characters[0] == '0' && characters + 2 < endCharacters) {
389         if ((characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
390             number = jsHexIntegerLiteral(characters, endCharacters);
391         else if ((characters[1] | 0x20) == 'o' && isASCIIOctalDigit(characters[2]))
392             number = jsOctalIntegerLiteral(characters, endCharacters);
393         else if ((characters[1] | 0x20) == 'b' && isASCIIBinaryDigit(characters[2]))
394             number = jsBinaryIntegerLiteral(characters, endCharacters);
395         else
396             number = jsStrDecimalLiteral(characters, endCharacters);
397     } else
398         number = jsStrDecimalLiteral(characters, endCharacters);
399
400     // Allow trailing white space.
401     for (; characters < endCharacters; ++characters) {
402         if (!isStrWhiteSpace(*characters))
403             break;
404     }
405     if (characters != endCharacters)
406         return PNaN;
407
408     return number;
409 }
410
411 // See ecma-262 6th 11.8.3
412 double jsToNumber(StringView s)
413 {
414     unsigned size = s.length();
415
416     if (size == 1) {
417         UChar c = s[0];
418         if (isASCIIDigit(c))
419             return c - '0';
420         if (isStrWhiteSpace(c))
421             return 0;
422         return PNaN;
423     }
424
425     if (s.is8Bit())
426         return toDouble(s.characters8(), size);
427     return toDouble(s.characters16(), size);
428 }
429
430 static double parseFloat(StringView s)
431 {
432     unsigned size = s.length();
433
434     if (size == 1) {
435         UChar c = s[0];
436         if (isASCIIDigit(c))
437             return c - '0';
438         return PNaN;
439     }
440
441     if (s.is8Bit()) {
442         const LChar* data = s.characters8();
443         const LChar* end = data + size;
444
445         // Skip leading white space.
446         for (; data < end; ++data) {
447             if (!isStrWhiteSpace(*data))
448                 break;
449         }
450
451         // Empty string.
452         if (data == end)
453             return PNaN;
454
455         return jsStrDecimalLiteral(data, end);
456     }
457
458     const UChar* data = s.characters16();
459     const UChar* end = data + size;
460
461     // Skip leading white space.
462     for (; data < end; ++data) {
463         if (!isStrWhiteSpace(*data))
464             break;
465     }
466
467     // Empty string.
468     if (data == end)
469         return PNaN;
470
471     return jsStrDecimalLiteral(data, end);
472 }
473
474 EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
475 {
476     VM& vm = exec->vm();
477     auto scope = DECLARE_THROW_SCOPE(vm);
478
479     JSValue x = exec->argument(0);
480     if (!x.isString())
481         return JSValue::encode(x);
482
483     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
484     if (!globalObject->evalEnabled()) {
485         throwException(exec, scope, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
486         return JSValue::encode(jsUndefined());
487     }
488
489     String s = asString(x)->value(exec);
490     RETURN_IF_EXCEPTION(scope, encodedJSValue());
491
492     JSValue parsedObject;
493     if (s.is8Bit()) {
494         LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);
495         parsedObject = preparser.tryLiteralParse();
496     } else {
497         LiteralParser<UChar> preparser(exec, s.characters16(), s.length(), NonStrictJSON);
498         parsedObject = preparser.tryLiteralParse();
499     }
500     RETURN_IF_EXCEPTION(scope, encodedJSValue());
501     if (parsedObject)
502         return JSValue::encode(parsedObject);
503
504     SourceOrigin sourceOrigin = exec->callerSourceOrigin();
505     JSGlobalObject* calleeGlobalObject = exec->jsCallee()->globalObject(vm);
506     EvalExecutable* eval = IndirectEvalExecutable::create(exec, makeSource(s, sourceOrigin), false, DerivedContextType::None, false, EvalContextType::None);
507     EXCEPTION_ASSERT(!!scope.exception() == !eval);
508     if (!eval)
509         return encodedJSValue();
510
511     RELEASE_AND_RETURN(scope, JSValue::encode(vm.interpreter->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject->globalScope())));
512 }
513
514 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
515 {
516     JSValue value = exec->argument(0);
517     JSValue radixValue = exec->argument(1);
518
519     // Optimized handling for numbers:
520     // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
521     // results in a truncation to integer. In the case of -0, this is converted to 0.
522     //
523     // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
524     // however these values cannot be trivially truncated to int since 10^21 exceeds
525     // even the int64_t range. Negative numbers are a little trickier, the case for
526     // values in the range -10^21 < n <= -1 are similar to those for integer, but
527     // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
528     static const double tenToTheMinus6 = 0.000001;
529     static const double intMaxPlusOne = 2147483648.0;
530     if (value.isNumber()) {
531         double n = value.asNumber();
532         if (((n < intMaxPlusOne && n >= tenToTheMinus6) || !n) && radixValue.isUndefinedOrNull())
533             return JSValue::encode(jsNumber(static_cast<int32_t>(n)));
534     }
535
536     // If ToString throws, we shouldn't call ToInt32.
537     return toStringView(exec, value, [&] (StringView view) {
538         return JSValue::encode(jsNumber(parseInt(view, radixValue.toInt32(exec))));
539     });
540 }
541
542 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
543 {
544     auto viewWithString = exec->argument(0).toString(exec)->viewWithUnderlyingString(exec);
545     return JSValue::encode(jsNumber(parseFloat(viewWithString.view)));
546 }
547
548 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
549 {
550     static Bitmap<256> doNotUnescapeWhenDecodingURI = makeCharacterBitmap(
551         "#$&+,/:;=?@"
552     );
553
554     return JSValue::encode(decode(exec, doNotUnescapeWhenDecodingURI, true));
555 }
556
557 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
558 {
559     static Bitmap<256> emptyBitmap;
560     return JSValue::encode(decode(exec, emptyBitmap, true));
561 }
562
563 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
564 {
565     static Bitmap<256> doNotEscapeWhenEncodingURI = makeCharacterBitmap(
566         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
567         "abcdefghijklmnopqrstuvwxyz"
568         "0123456789"
569         "!#$&'()*+,-./:;=?@_~"
570     );
571
572     return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURI));
573 }
574
575 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
576 {
577     static Bitmap<256> doNotEscapeWhenEncodingURIComponent = makeCharacterBitmap(
578         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
579         "abcdefghijklmnopqrstuvwxyz"
580         "0123456789"
581         "!'()*-._~"
582     );
583
584     return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURIComponent));
585 }
586
587 EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
588 {
589     static Bitmap<256> doNotEscape = makeCharacterBitmap(
590         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
591         "abcdefghijklmnopqrstuvwxyz"
592         "0123456789"
593         "*+-./@_"
594     );
595
596     return JSValue::encode(toStringView(exec, exec->argument(0), [&] (StringView view) {
597         StringBuilder builder;
598         if (view.is8Bit()) {
599             const LChar* c = view.characters8();
600             for (unsigned k = 0; k < view.length(); k++, c++) {
601                 int u = c[0];
602                 if (doNotEscape.get(static_cast<LChar>(u)))
603                     builder.append(*c);
604                 else {
605                     builder.append('%');
606                     appendByteAsHex(u, builder);
607                 }
608             }
609             return jsString(exec, builder.toString());
610         }
611
612         const UChar* c = view.characters16();
613         for (unsigned k = 0; k < view.length(); k++, c++) {
614             UChar u = c[0];
615             if (u >= doNotEscape.size()) {
616                 builder.appendLiteral("%u");
617                 appendByteAsHex(u >> 8, builder);
618                 appendByteAsHex(u & 0xFF, builder);
619             } else if (doNotEscape.get(static_cast<LChar>(u)))
620                 builder.append(*c);
621             else {
622                 builder.append('%');
623                 appendByteAsHex(u, builder);
624             }
625         }
626
627         return jsString(exec, builder.toString());
628     }));
629 }
630
631 EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
632 {
633     return JSValue::encode(toStringView(exec, exec->argument(0), [&] (StringView view) {
634         // We use int for k and length intentionally since we would like to evaluate
635         // the condition `k <= length -6` even if length is less than 6.
636         int k = 0;
637         int length = view.length();
638
639         StringBuilder builder;
640         builder.reserveCapacity(length);
641
642         if (view.is8Bit()) {
643             const LChar* characters = view.characters8();
644             LChar convertedLChar;
645             while (k < length) {
646                 const LChar* c = characters + k;
647                 if (c[0] == '%' && k <= length - 6 && c[1] == 'u') {
648                     if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
649                         builder.append(Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]));
650                         k += 6;
651                         continue;
652                     }
653                 } else if (c[0] == '%' && k <= length - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
654                     convertedLChar = LChar(Lexer<LChar>::convertHex(c[1], c[2]));
655                     c = &convertedLChar;
656                     k += 2;
657                 }
658                 builder.append(*c);
659                 k++;
660             }
661         } else {
662             const UChar* characters = view.characters16();
663
664             while (k < length) {
665                 const UChar* c = characters + k;
666                 UChar convertedUChar;
667                 if (c[0] == '%' && k <= length - 6 && c[1] == 'u') {
668                     if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
669                         convertedUChar = Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]);
670                         c = &convertedUChar;
671                         k += 5;
672                     }
673                 } else if (c[0] == '%' && k <= length - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
674                     convertedUChar = UChar(Lexer<UChar>::convertHex(c[1], c[2]));
675                     c = &convertedUChar;
676                     k += 2;
677                 }
678                 k++;
679                 builder.append(*c);
680             }
681         }
682
683         return jsString(exec, builder.toString());
684     }));
685 }
686
687 EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState* exec)
688 {
689     VM& vm = exec->vm();
690     auto scope = DECLARE_THROW_SCOPE(vm);
691     return throwVMTypeError(exec, scope);
692 }
693
694 EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeErrorArgumentsCalleeAndCaller(ExecState* exec)
695 {
696     VM& vm = exec->vm();
697     auto scope = DECLARE_THROW_SCOPE(vm);
698     return throwVMTypeError(exec, scope, "'arguments', 'callee', and 'caller' cannot be accessed in this context.");
699 }
700
701 EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
702 {
703     VM& vm = exec->vm();
704     auto scope = DECLARE_THROW_SCOPE(vm);
705
706     JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
707     if (thisValue.isUndefinedOrNull())
708         return throwVMError(exec, scope, createNotAnObjectError(exec, thisValue));
709
710     JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
711     if (!thisObject) {
712         JSObject* prototype = thisValue.synthesizePrototype(exec);
713         EXCEPTION_ASSERT(!!scope.exception() == !prototype);
714         if (UNLIKELY(!prototype))
715             return JSValue::encode(JSValue());
716         return JSValue::encode(prototype);
717     }
718
719     RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPrototype(vm, exec)));
720 }
721
722 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
723 {
724     VM& vm = exec->vm();
725     auto scope = DECLARE_THROW_SCOPE(vm);
726
727     JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
728     if (thisValue.isUndefinedOrNull())
729         return throwVMTypeError(exec, scope, ObjectProtoCalledOnNullOrUndefinedError);
730
731     JSValue value = exec->argument(0);
732
733     JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue);
734
735     // Setting __proto__ of a primitive should have no effect.
736     if (!thisObject)
737         return JSValue::encode(jsUndefined());
738
739     // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
740     if (!value.isObject() && !value.isNull())
741         return JSValue::encode(jsUndefined());
742
743     scope.release();
744     bool shouldThrowIfCantSet = true;
745     thisObject->setPrototype(vm, exec, value, shouldThrowIfCantSet);
746     return JSValue::encode(jsUndefined());
747 }
748
749 EncodedJSValue JSC_HOST_CALL globalFuncHostPromiseRejectionTracker(ExecState* exec)
750 {
751     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
752     VM& vm = globalObject->vm();
753     auto scope = DECLARE_THROW_SCOPE(vm);
754
755     if (!globalObject->globalObjectMethodTable()->promiseRejectionTracker)
756         return JSValue::encode(jsUndefined());
757
758     JSPromise* promise = jsCast<JSPromise*>(exec->argument(0));
759     JSValue operationValue = exec->argument(1);
760
761     ASSERT(operationValue.isNumber());
762     auto operation = static_cast<JSPromiseRejectionOperation>(operationValue.toUInt32(exec));
763     ASSERT(operation == JSPromiseRejectionOperation::Reject || operation == JSPromiseRejectionOperation::Handle);
764     scope.assertNoException();
765
766     globalObject->globalObjectMethodTable()->promiseRejectionTracker(globalObject, exec, promise, operation);
767     RETURN_IF_EXCEPTION(scope, { });
768
769     return JSValue::encode(jsUndefined());
770 }
771
772 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState* exec)
773 {
774     dataLog(exec->argument(0).toWTFString(exec), "\n");
775     return JSValue::encode(jsUndefined());
776 }
777
778 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinDescribe(ExecState* exec)
779 {
780     return JSValue::encode(jsString(exec, toString(exec->argument(0))));
781 }
782
783 EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState* exec)
784 {
785     VM& vm = exec->vm();
786     auto throwScope = DECLARE_THROW_SCOPE(vm);
787
788     auto* globalObject = exec->lexicalGlobalObject();
789
790     auto* promise = JSPromiseDeferred::tryCreate(exec, globalObject);
791     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
792
793     auto catchScope = DECLARE_CATCH_SCOPE(vm);
794     auto reject = [&] (JSValue rejectionReason) {
795         catchScope.clearException();
796         promise->reject(exec, rejectionReason);
797         catchScope.clearException();
798         return JSValue::encode(promise->promise());
799     };
800
801     auto sourceOrigin = exec->callerSourceOrigin();
802     RELEASE_ASSERT(exec->argumentCount() == 1);
803     auto* specifier = exec->uncheckedArgument(0).toString(exec);
804     if (Exception* exception = catchScope.exception())
805         return reject(exception->value());
806
807     // We always specify parameters as undefined. Once dynamic import() starts accepting fetching parameters,
808     // we should retrieve this from the arguments.
809     JSValue parameters = jsUndefined();
810     auto* internalPromise = globalObject->moduleLoader()->importModule(exec, specifier, parameters, sourceOrigin);
811     if (Exception* exception = catchScope.exception())
812         return reject(exception->value());
813     promise->resolve(exec, internalPromise);
814
815     catchScope.clearException();
816     return JSValue::encode(promise->promise());
817 }
818
819 EncodedJSValue JSC_HOST_CALL globalFuncPropertyIsEnumerable(ExecState* exec)
820 {
821     VM& vm = exec->vm();
822     auto scope = DECLARE_THROW_SCOPE(vm);
823
824     RELEASE_ASSERT(exec->argumentCount() == 2);
825     JSObject* object = jsCast<JSObject*>(exec->uncheckedArgument(0));
826     auto propertyName = exec->uncheckedArgument(1).toPropertyKey(exec);
827     RETURN_IF_EXCEPTION(scope, encodedJSValue());
828
829     scope.release();
830     PropertyDescriptor descriptor;
831     bool enumerable = object->getOwnPropertyDescriptor(exec, propertyName, descriptor) && descriptor.enumerable();
832     return JSValue::encode(jsBoolean(enumerable));
833 }
834
835 #if ENABLE(INTL)
836 EncodedJSValue JSC_HOST_CALL globalFuncDateTimeFormat(ExecState* exec)
837 {
838     VM& vm = exec->vm();
839     auto scope = DECLARE_THROW_SCOPE(vm);
840
841     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
842     IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, globalObject->intlObject()->dateTimeFormatStructure());
843     dateTimeFormat->initializeDateTimeFormat(*exec, exec->argument(0), exec->argument(1));
844     RETURN_IF_EXCEPTION(scope, encodedJSValue());
845     double value = exec->argument(2).toNumber(exec);
846     RETURN_IF_EXCEPTION(scope, encodedJSValue());
847     RELEASE_AND_RETURN(scope, JSValue::encode(dateTimeFormat->format(*exec, value)));
848 }
849 #endif
850
851 } // namespace JSC