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