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