• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/builtins/builtins_global.h"
17 
18 #include <random>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 #include "ecmascript/base/number_helper.h"
24 #include "ecmascript/base/string_helper.h"
25 #include "ecmascript/ecma_macros.h"
26 #include "ecmascript/js_function.h"
27 #include "ecmascript/mem/c_containers.h"
28 #include "ecmascript/module/js_module_deregister.h"
29 #include "ecmascript/stubs/runtime_stubs.h"
30 #include "ecmascript/tagged_array-inl.h"
31 
32 namespace panda::ecmascript::builtins {
33 using NumberHelper = base::NumberHelper;
34 using StringHelper = base::StringHelper;
35 // bitmap for "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" + "@*+-./"
36 constexpr std::uint8_t ESCAPE_BIT_MAP[128] = {
37     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
40     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
41     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
42     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
43     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
44     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
45 constexpr std::uint8_t ESCAPE_HEX_TO_CHAR[16] = {
46     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
47 };
48 constexpr std::uint8_t ESCAPE_CHAR_TO_HEX[128] = {
49     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
53     0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55     0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
57 };
58 constexpr std::uint8_t ESCAPE_HEX_MASK = 0xf;
59 constexpr std::uint8_t ESCAPE_HEX_BIT4 = 4;
60 constexpr std::uint8_t ESCAPE_HEX_BIT8 = 8;
61 constexpr std::uint8_t ESCAPE_HEX_BIT12 = 12;
62 constexpr std::uint8_t ESCAPE_CHAR_OFFSET2 = 2;
63 constexpr std::uint8_t ESCAPE_CHAR_OFFSET3 = 3;
64 constexpr std::uint8_t ESCAPE_CHAR_OFFSET4 = 4;
65 constexpr std::uint8_t ESCAPE_CHAR_OFFSET5 = 5;
66 constexpr std::uint16_t CHAR16_LETTER_NULL = u'\0';
67 
68 // 18.2.1
NotSupportEval(EcmaRuntimeCallInfo * msg)69 JSTaggedValue BuiltinsGlobal::NotSupportEval(EcmaRuntimeCallInfo *msg)
70 {
71     JSThread *thread = msg->GetThread();
72     BUILTINS_API_TRACE(thread, Global, NotSupportEval);
73     [[maybe_unused]] EcmaHandleScope handleScope(thread);
74     THROW_TYPE_ERROR_AND_RETURN(thread, "not support eval()", JSTaggedValue::Exception());
75 }
76 
77 // 18.2.2
IsFinite(EcmaRuntimeCallInfo * msg)78 JSTaggedValue BuiltinsGlobal::IsFinite(EcmaRuntimeCallInfo *msg)
79 {
80     ASSERT(msg);
81     JSThread *thread = msg->GetThread();
82     BUILTINS_API_TRACE(thread, Global, IsFinite);
83     [[maybe_unused]] EcmaHandleScope handleScope(thread);
84     JSHandle<JSTaggedValue> numberInput = GetCallArg(msg, 0);
85     // 1. Let num be ToNumber(number).
86     JSTaggedNumber number = JSTaggedValue::ToNumber(thread, numberInput);
87     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
88     // 3. If num is NaN, +Infinite, or -Infinite, return false.
89     // 4. Otherwise, return true.
90     if (std::isfinite(number.GetNumber())) {
91         return GetTaggedBoolean(true);
92     }
93     return GetTaggedBoolean(false);
94 }
95 
96 // 18.2.3
IsNaN(EcmaRuntimeCallInfo * msg)97 JSTaggedValue BuiltinsGlobal::IsNaN(EcmaRuntimeCallInfo *msg)
98 {
99     ASSERT(msg);
100     JSThread *thread = msg->GetThread();
101     BUILTINS_API_TRACE(thread, Global, IsNaN);
102     [[maybe_unused]] EcmaHandleScope handleScope(thread);
103     JSHandle<JSTaggedValue> numberInput = GetCallArg(msg, 0);
104     // 1. Let num be ToNumber(number).
105     JSTaggedNumber number = JSTaggedValue::ToNumber(thread, numberInput);
106     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
107 
108     // 3. If num is NaN, return true.
109     if (std::isnan(number.GetNumber())) {
110         return GetTaggedBoolean(true);
111     }
112     // 4. Otherwise, return false.
113     return GetTaggedBoolean(false);
114 }
115 
IsUnescapedURI(uint16_t ch)116 bool BuiltinsGlobal::IsUnescapedURI(uint16_t ch)
117 {
118     if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
119         return true;
120     }
121     return IsInMarkURISet(ch);
122 }
123 
IsInUnescapedURISet(uint16_t ch)124 bool BuiltinsGlobal::IsInUnescapedURISet(uint16_t ch)
125 {
126     if (ch == '#') {
127         return true;
128     }
129     return IsUnescapedURI(ch) || IsReservedURI(ch);
130 }
131 
IsInReservedURISet(uint16_t ch)132 bool BuiltinsGlobal::IsInReservedURISet(uint16_t ch)
133 {
134     if (ch == '#') {
135         return true;
136     }
137     return IsReservedURI(ch);
138 }
139 
IsReservedURI(uint16_t ch)140 bool BuiltinsGlobal::IsReservedURI(uint16_t ch)
141 {
142     std::u16string str(u";/?:@&=+$,");
143     std::u16string::size_type index = str.find(ch);
144     return (index != std::u16string::npos);
145 }
146 
IsInMarkURISet(uint16_t ch)147 bool BuiltinsGlobal::IsInMarkURISet(uint16_t ch)
148 {
149     std::u16string str(u"-_.!~*'()");
150     std::u16string::size_type index = str.find(ch);
151     return (index != std::u16string::npos);
152 }
153 
IsHexDigits(uint16_t ch)154 bool BuiltinsGlobal::IsHexDigits(uint16_t ch)
155 {
156     return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
157 }
158 
159 // 18.2.6
DecodeURI(EcmaRuntimeCallInfo * msg)160 JSTaggedValue BuiltinsGlobal::DecodeURI(EcmaRuntimeCallInfo *msg)
161 {
162     ASSERT(msg);
163     JSThread *thread = msg->GetThread();
164     BUILTINS_API_TRACE(thread, Global, DecodeURI);
165     [[maybe_unused]] EcmaHandleScope handleScope(thread);
166     // 1. Let uriString be ToString(encodedURI).
167     // 2. ReturnIfAbrupt(uriString).
168     JSHandle<EcmaString> uriString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
169     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
170 
171     // 3. Let reservedURISet be a String containing one instance of each code unit valid in uriReserved plus "#".
172     // 4. Return Decode(uriString, reservedURISet).
173     return Decode(thread, uriString, IsInReservedURISet);
174 }
175 
EncodeURI(EcmaRuntimeCallInfo * msg)176 JSTaggedValue BuiltinsGlobal::EncodeURI(EcmaRuntimeCallInfo *msg)
177 {
178     ASSERT(msg);
179     JSThread *thread = msg->GetThread();
180     BUILTINS_API_TRACE(thread, Global, EncodeURI);
181     [[maybe_unused]] EcmaHandleScope handleScope(thread);
182     // 1. Let uriString be ToString(uri).
183     // 2. ReturnIfAbrupt(uriString).
184     JSHandle<EcmaString> uriString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
185     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
186 
187     // 3. Let unescapedURISet be a String containing one instance of
188     //    each code unit valid in uriReserved and uriUnescaped plus "#".
189     // 4. Return Encode(uriString, unescapedURISet).
190     return Encode(thread, uriString, IsInUnescapedURISet);
191 }
192 
DecodeURIComponent(EcmaRuntimeCallInfo * msg)193 JSTaggedValue BuiltinsGlobal::DecodeURIComponent(EcmaRuntimeCallInfo *msg)
194 {
195     ASSERT(msg);
196     JSThread *thread = msg->GetThread();
197     BUILTINS_API_TRACE(thread, Global, DecodeURIComponent);
198     [[maybe_unused]] EcmaHandleScope handleScope(thread);
199     // 1. Let componentString be ToString(encodedURIComponent).
200     // 2. ReturnIfAbrupt(componentString).
201     JSHandle<EcmaString> componentString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
202     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
203 
204     // 3. Let reservedURIComponentSet be the empty String.
205     // 4. Return Decode(componentString, reservedURIComponentSet).
206     return Decode(thread, componentString, []([[maybe_unused]] uint16_t unused) { return false; });
207 }
208 
EncodeURIComponent(EcmaRuntimeCallInfo * msg)209 JSTaggedValue BuiltinsGlobal::EncodeURIComponent(EcmaRuntimeCallInfo *msg)
210 {
211     ASSERT(msg);
212     JSThread *thread = msg->GetThread();
213     BUILTINS_API_TRACE(thread, Global, EncodeURIComponent);
214     [[maybe_unused]] EcmaHandleScope handleScope(thread);
215     // 1. Let componentString be ToString(uriComponent).
216     // 2. ReturnIfAbrupt(componentString).
217     JSHandle<EcmaString> componentString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
218     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
219 
220     // 3. Let unescapedURIComponentSet be a String containing one instance of each code unit valid in uriUnescaped.
221     // 4. Return Encode(componentString, unescapedURIComponentSet).
222     return Encode(thread, componentString, IsUnescapedURI);
223 }
224 
225 // Runtime Semantics
Encode(JSThread * thread,const JSHandle<EcmaString> & str,judgURIFunc IsInURISet)226 JSTaggedValue BuiltinsGlobal::Encode(JSThread *thread, const JSHandle<EcmaString> &str, judgURIFunc IsInURISet)
227 {
228     BUILTINS_API_TRACE(thread, Global, Encode);
229     // 1. Let strLen be the number of code units in string.
230     uint32_t strLen = EcmaStringAccessor(str).GetLength();
231     // 2. Let R be the empty String.
232     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
233     std::u16string resStr;
234 
235     // 3. Let k be 0.
236     // 4. Repeat
237     uint32_t k = 0;
238     while (true) {
239         // a. If k equals strLen, return R.
240         if (k == strLen) {
241             auto *uint16tData = reinterpret_cast<uint16_t *>(resStr.data());
242             uint32_t resSize = resStr.size();
243             return factory->NewFromUtf16Literal(uint16tData, resSize).GetTaggedValue();
244         }
245 
246         // b. Let C be the code unit at index k within string.
247         // c. If C is in unescapedSet, then
248         //   i. Let S be a String containing only the code unit C.
249         //   ii. Let R be a new String value computed by concatenating the previous value of R and S.
250         // d. Else C is not in unescapedSet,
251         uint16_t cc = EcmaStringAccessor(str).Get(k);
252         if (IsInURISet(cc)) {
253             std::u16string sStr = StringHelper::Utf16ToU16String(&cc, 1);
254             resStr.append(sStr);
255         } else {
256             // i. If the code unit value of C is not less than 0xDC00 and not greater than 0xDFFF,
257             //    throw a URIError exception.
258             if (cc >= base::utf_helper::DECODE_TRAIL_LOW && cc <= base::utf_helper::DECODE_TRAIL_HIGH) {
259                 THROW_URI_ERROR_AND_RETURN(thread, "EncodeURI: The format of the URI to be parsed is incorrect",
260                                            JSTaggedValue::Exception());
261             }
262 
263             // ii. If the code unit value of C is less than 0xD800 or greater than 0xDBFF, then
264             //    1. Let V be the code unit value of C.
265             // iii. Else,
266             //    1. Increase k by 1.
267             //    2. If k equals strLen, throw a URIError exception.
268             //    3. Let kChar be the code unit value of the code unit at index k within string.
269             //    4. If kChar is less than 0xDC00 or greater than 0xDFFF, throw a URIError exception.
270             //    5. Let V be UTF16Decode(C, kChar).
271             uint32_t vv;
272             if (cc < base::utf_helper::DECODE_LEAD_LOW || cc > base::utf_helper::DECODE_LEAD_HIGH) {
273                 vv = cc;
274             } else {
275                 k++;
276                 if (k == strLen) {
277                     THROW_URI_ERROR_AND_RETURN(thread, "k is invalid", JSTaggedValue::Exception());
278                 }
279                 uint16_t kc = EcmaStringAccessor(str).Get(k);
280                 if (kc < base::utf_helper::DECODE_TRAIL_LOW || kc > base::utf_helper::DECODE_TRAIL_HIGH) {
281                     THROW_URI_ERROR_AND_RETURN(thread, "EncodeURI: The format of the URI to be parsed is incorrect",
282                                                JSTaggedValue::Exception());
283                 }
284                 vv = base::utf_helper::UTF16Decode(cc, kc);
285             }
286 
287             // iv. Let Octets be the array of octets resulting by applying the UTF-8 transformation to V,
288             //     and let L be the array size.
289             // v. Let j be 0.
290             // vi. Repeat, while j < L
291             //    1. Let jOctet be the value at index j within Octets.
292             //    2. Let S be a String containing three code units "%XY" where XY are two uppercase hexadecimal
293             //       digits encoding the value of jOctet.
294             //    3. Let R be a new String value computed by concatenating the previous value of R and S.
295             //    4. Increase j by 1.
296             std::string oct = StringHelper::Utf32ToString(vv);
297             std::string hexStr("0123456789ABCDEF");
298 
299             uint32_t length = oct.length();
300             std::stringstream tmpStr;
301             for (uint32_t j = 0; j < length; j++) {
302                 uint8_t joct = static_cast<uint8_t>(oct.at(j));
303                 tmpStr << '%' << hexStr.at((joct >> 4U) & BIT_MASK)  // NOLINT
304                        << hexStr.at(joct & BIT_MASK);                // 4: means shift right by 4 digits
305             }
306             resStr.append(StringHelper::StringToU16string(tmpStr.str()));
307         }
308 
309         // e. Increase k by 1.
310         k++;
311     }
312 }
313 
GetValueFromTwoHex(uint16_t front,uint16_t behind)314 uint8_t BuiltinsGlobal::GetValueFromTwoHex(uint16_t front, uint16_t behind)
315 {
316     ASSERT(IsHexDigits(front) && IsHexDigits(behind));
317     std::u16string hexString(u"0123456789ABCDEF");
318 
319     size_t idxf = StringHelper::FindFromU16ToUpper(hexString, &front);
320     size_t idxb = StringHelper::FindFromU16ToUpper(hexString, &behind);
321     uint8_t res = ((idxf << 4U) | idxb) & BIT_MASK_FF;  // NOLINT 4: means shift left by 4 digits
322     return res;
323 }
324 
GetValueFromHexString(const JSHandle<EcmaString> & string)325 uint16_t BuiltinsGlobal::GetValueFromHexString(const JSHandle<EcmaString> &string)
326 {
327     uint32_t size = EcmaStringAccessor(string).GetLength();
328     ASSERT(size > 0 && size <= 4); // NOLINT 4: means 4 hex digits
329     std::u16string hexString(u"0123456789ABCDEF");
330 
331     uint16_t ret = 0;
332     for (uint32_t i = 0; i < size; ++i) {
333         uint16_t ch = EcmaStringAccessor(string).Get(i);
334         size_t idx = StringHelper::FindFromU16ToUpper(hexString, &ch);
335         ret = ((ret << 4U) | idx) & BIT_MASK_4F; // NOLINT 4: means shift left by 4
336     }
337     return ret;
338 }
339 
340 // 22.1.3.17.2 StringPad ( S, maxLength, fillString, placement )
StringPad(JSThread * thread,const JSHandle<EcmaString> & source,uint32_t maxLength,const JSHandle<EcmaString> & fillString,Placement placement)341 EcmaString *BuiltinsGlobal::StringPad(JSThread *thread, const JSHandle<EcmaString> &source,
342                                       uint32_t maxLength, const JSHandle<EcmaString> &fillString,
343                                       Placement placement)
344 {
345     // 1. Let stringLength be the length of S.
346     uint32_t stringLength = EcmaStringAccessor(source).GetLength();
347     // 2. If maxLength ≤ stringLength, return S.
348     if (maxLength <= stringLength) {
349         return *source;
350     }
351     // 3. If fillString is the empty String, return S.
352     uint32_t targetStrLen = EcmaStringAccessor(fillString).GetLength();
353     if (targetStrLen == 0) {
354         return *source;
355     }
356     // 4. Let fillLen be maxLength - stringLength.
357     uint32_t fillLen = maxLength - stringLength;
358     EcmaVM *vm = thread->GetEcmaVM();
359     //5. Let truncatedStringFiller be the String value consisting of repeated concatenations
360     // of fillString truncated to length fillLen.
361     uint32_t repeatTimes = std::ceil(fillLen / targetStrLen);
362     EcmaString *p = nullptr;
363     JSHandle<EcmaString> stringFiller = vm->GetFactory()->NewFromStdString(std::string("\0"));
364     for (uint32_t k = 0; k < repeatTimes; ++k) {
365         p = EcmaStringAccessor::Concat(vm, stringFiller, fillString);
366         stringFiller = JSHandle<EcmaString>(thread, p);
367     }
368     JSHandle<EcmaString> truncatedStringFiller(thread,
369         EcmaStringAccessor::FastSubString(vm, stringFiller, 0, fillLen));
370     // 6. If placement is start, return the string-concatenation of truncatedStringFiller and S.
371     // 7. Else, return the string-concatenation of S and truncatedStringFiller.
372     if (placement == Placement::START) {
373         return EcmaStringAccessor::Concat(vm, truncatedStringFiller, source);
374     } else {
375         return EcmaStringAccessor::Concat(vm, source, truncatedStringFiller);
376     }
377 }
378 
379 // Static Semantics: UTF16SurrogatePairToCodePoint ( lead, trail )
UTF16SurrogatePairToCodePoint(uint16_t lead,uint16_t trail)380 uint16_t BuiltinsGlobal::UTF16SurrogatePairToCodePoint(uint16_t lead, uint16_t trail)
381 {
382     // 1. Assert: lead is a leading surrogate and trail is a trailing surrogate.
383     ASSERT(IsUTF16HighSurrogate(lead) && IsUTF16LowSurrogate(trail));
384     // 2. Let cp be (lead - 0xD800) × 0x400 + (trail - 0xDC00) + 0x10000.
385     uint16_t cp = ((lead - 0xD800) << 10UL) + (trail - 0xDC00) + 0x10000;
386     // 3. Return the code point cp.
387     return cp;
388 }
389 
390 // 11.1.5 Static Semantics: StringToCodePoints ( string )
StringToCodePoints(JSThread * thread,const JSHandle<EcmaString> & string)391 EcmaString *BuiltinsGlobal::StringToCodePoints(JSThread *thread, const JSHandle<EcmaString> &string)
392 {
393     // 1. Let codePoints be a new empty List.
394     std::u16string codePoints;
395     // 2. Let size be the length of string.
396     uint32_t size = EcmaStringAccessor(string).GetLength();
397     // 3. Let position be 0.
398     uint32_t position = 0;
399     // 4. Repeat, while position < size,
400     //    a. Let cp be CodePointAt(string, position).
401     //    b. Append cp.[[CodePoint]] to codePoints.
402     //    c. Set position to position + cp.[[CodeUnitCount]].
403     while (position < size) {
404         // i.Let first be the code unit at index position within string.
405         uint16_t first = EcmaStringAccessor(string).Get(position);
406         uint16_t cp = first - CHAR16_LETTER_NULL;
407         uint8_t codeUnitCount = 0;
408         bool isUnpairedSurrogate = false;
409         // ii. If first is neither a leading surrogate nor a trailing surrogate, then
410         //   a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }.
411         if (!IsUTF16HighSurrogate(first) && !IsUTF16LowSurrogate(first)) {
412             codeUnitCount = 1; // 1 means: code unit count
413             isUnpairedSurrogate = false;
414         } else if (IsUTF16HighSurrogate(first) || position + 1 == size) {
415             // iii. If first is a trailing surrogate or position + 1 = size, then
416             //   a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.
417             codeUnitCount = 1;
418             isUnpairedSurrogate = true;
419         } else {
420             // iv. Let second be the code unit at index position + 1 within string.
421             uint16_t second = EcmaStringAccessor(string).Get(position + 1);
422             // v. If second is not a trailing surrogate, then
423             //   a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.
424             if (!IsUTF16LowSurrogate(second)) {
425                 codeUnitCount = 1; // 1 means: code unit count
426                 isUnpairedSurrogate = true;
427             } else {
428             // vi. Set cp to UTF16SurrogatePairToCodePoint(first, second).
429             // vii. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }.
430                 cp = UTF16SurrogatePairToCodePoint(first, second);
431                 codeUnitCount = 2; // 2 means: code unit count
432                 isUnpairedSurrogate = false;
433             }
434         }
435         codePoints.push_back(cp);
436         position = position + codeUnitCount;
437     }
438     // 5. Return codePoints.
439     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
440     uint16_t *ptr = reinterpret_cast<uint16_t *>(codePoints.data());
441     JSHandle<EcmaString> codePointsString = factory->NewFromUtf16Literal(ptr, codePoints.size());
442     return *codePointsString;
443 }
444 
445 // Runtime Semantics
Decode(JSThread * thread,const JSHandle<EcmaString> & str,judgURIFunc IsInURISet)446 JSTaggedValue BuiltinsGlobal::Decode(JSThread *thread, const JSHandle<EcmaString> &str, judgURIFunc IsInURISet)
447 {
448     BUILTINS_API_TRACE(thread, Global, Decode);
449     // 1. Let strLen be the number of code units in string.
450     int32_t strLen = static_cast<int32_t>(EcmaStringAccessor(str).GetLength());
451     // 2. Let R be the empty String.
452     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
453     std::u16string resStr;
454 
455     // 3. Let k be 0.
456     // 4. Repeat
457     int32_t k = 0;
458     while (true) {
459         // a. If k equals strLen, return R.
460         if (k == strLen) {
461             auto *uint16tData = reinterpret_cast<uint16_t *>(resStr.data());
462             uint32_t resSize = resStr.size();
463             return factory->NewFromUtf16Literal(uint16tData, resSize).GetTaggedValue();
464         }
465 
466         // b. Let C be the code unit at index k within string.
467         // c. If C is not "%", then
468         //    i. Let S be the String containing only the code unit C.
469         // d. Else C is "%",
470         //   i. Let start be k.
471         //   iv. Let B be the 8-bit value represented by the two hexadecimal digits at index (k + 1) and (k + 2).
472         //   v. Increase k by 2.
473         //   vi. If the most significant bit in B is 0, then
474         //      1. Let C be the code unit with code unit value B.
475         //      2. If C is not in reservedSet, then
476         //         a. Let S be the String containing only the code unit C.
477         //      3. Else C is in reservedSet,
478         //         a. Let S be the substring of string from index start to index k inclusive.
479         uint16_t cc = EcmaStringAccessor(str).Get(k);
480         std::u16string sStr;
481         if (cc != '%') {
482             if (cc == 0 && strLen == 1) {
483                 JSHandle<EcmaString> tmpEcmaString = factory->NewFromUtf16Literal(&cc, 1);
484                 return tmpEcmaString.GetTaggedValue();
485             }
486             sStr = StringHelper::Utf16ToU16String(&cc, 1);
487         } else {
488             [[maybe_unused]] uint32_t start = static_cast<uint32_t>(k);
489 
490             // ii. If k + 2 is greater than or equal to strLen, throw a URIError exception.
491             // iii. If the code units at index (k+1) and (k + 2) within string do not represent hexadecimal digits,
492             //      throw a URIError exception.
493             if ((k + 2) >= strLen) {  // 2: means plus 2
494                 THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
495                                            JSTaggedValue::Exception());
496             }
497             if (!(IsHexDigits(EcmaStringAccessor(str).Get(k + 1)) &&
498                 IsHexDigits(EcmaStringAccessor(str).Get(k + 2)))) {  // 2: means plus 2
499                 THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
500                                            JSTaggedValue::Exception());
501             }
502 
503             uint16_t frontChar = EcmaStringAccessor(str).Get(k + 1);
504             uint16_t behindChar = EcmaStringAccessor(str).Get(k + 2);  // 2: means plus 2
505             uint8_t bb = GetValueFromTwoHex(frontChar, behindChar);
506             k += 2;  // 2: means plus 2
507             if ((bb & BIT_MASK_ONE) == 0) {
508                 if (!IsInURISet(bb)) {
509                     sStr = StringHelper::Utf8ToU16String(&bb, 1);
510                 } else {
511                     auto substr = EcmaStringAccessor::FastSubString(
512                         thread->GetEcmaVM(), str, start, static_cast<uint32_t>(k) - start + 1U);
513                     sStr = StringHelper::StringToU16string(
514                         EcmaStringAccessor(substr).ToStdString(StringConvertedUsage::LOGICOPERATION));
515                 }
516             } else {
517                 // vii. Else the most significant bit in B is 1,
518                 //   1. Let n be the smallest nonnegative integer such that (B << n) & 0x80 is equal to 0.
519                 //   3. Let Octets be an array of 8-bit integers of size n.
520                 //   4. Put B into Octets at index 0.
521                 //   6. Let j be 1.
522                 //   7. Repeat, while j < n
523                 //     a. Increase k by 1.
524                 //     d. Let B be the 8-bit value represented by the two hexadecimal digits at
525                 //        index (k + 1) and (k + 2).
526                 //     f. Increase k by 2.
527                 //     g. Put B into Octets at index j.
528                 //     h. Increase j by 1.
529                 //   9. If V < 0x10000, then
530                 //     a. Let C be the code unit V.
531                 //     b. If C is not in reservedSet, then
532                 //        i. Let S be the String containing only the code unit C.
533                 //     c. Else C is in reservedSet,
534                 //        i. Let S be the substring of string from index start to index k inclusive.
535                 //   10. Else V ≥ 0x10000,
536                 //     a. Let L be (((V – 0x10000) & 0x3FF) + 0xDC00).
537                 //     b. Let H be ((((V – 0x10000) >> 10) & 0x3FF) + 0xD800).
538                 //     c. Let S be the String containing the two code units H and L.
539                 int32_t n = 0;
540                 while ((((static_cast<uint32_t>(bb) << static_cast<uint32_t>(n)) & BIT_MASK_ONE) != 0)) {
541                     n++;
542                     if (n > 4) { // 4 : 4 means less than 4
543                         break;
544                     }
545                 }
546                 // 2. If n equals 1 or n is greater than 4, throw a URIError exception.
547                 if ((n == 1) || (n > 4)) {  // 4: means greater than 4
548                     THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
549                                                JSTaggedValue::Exception());
550                 }
551 
552                 std::vector<uint8_t> oct = {bb};
553 
554                 // 5. If k + (3 × (n – 1)) is greater than or equal to strLen, throw a URIError exception.
555                 if (k + (3 * (n - 1)) >= strLen) {  // 3: means multiply by 3
556                     THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
557                                                JSTaggedValue::Exception());
558                 }
559                 int32_t j = 1;
560                 while (j < n) {
561                     k++;
562                     uint16_t codeUnit = EcmaStringAccessor(str).Get(k);
563                     // b. If the code unit at index k within string is not "%", throw a URIError exception.
564                     // c. If the code units at index (k +1) and (k + 2) within string do not represent hexadecimal
565                     //    digits, throw a URIError exception.
566                     if (!(codeUnit == '%')) {
567                         THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
568                                                    JSTaggedValue::Exception());
569                     }
570                     if (!(IsHexDigits(EcmaStringAccessor(str).Get(k + 1)) &&
571                         IsHexDigits(EcmaStringAccessor(str).Get(k + 2)))) {  // 2: means plus 2
572                         THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
573                                                    JSTaggedValue::Exception());
574                     }
575 
576                     uint16_t frontChart = EcmaStringAccessor(str).Get(k + 1);
577                     uint16_t behindChart = EcmaStringAccessor(str).Get(k + 2);  // 2: means plus 2
578                     bb = GetValueFromTwoHex(frontChart, behindChart);
579                     // e. If the two most significant bits in B are not 10, throw a URIError exception.
580                     if (!((bb & BIT_MASK_TWO) == BIT_MASK_ONE)) {
581                         THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
582                                                    JSTaggedValue::Exception());
583                     }
584 
585                     k += 2;  // 2: means plus 2
586                     oct.push_back(bb);
587                     j++;
588                 }
589 
590                 // 8. Let V be the value obtained by applying the UTF-8 transformation to Octets, that is,
591                 //     from an array of octets into a 21-bit value. If Octets does not contain a valid UTF-8 encoding of
592                 //     a Unicode code point throw a URIError exception.
593                 if (!base::utf_helper::IsValidUTF8(oct)) {
594                     THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
595                                                JSTaggedValue::Exception());
596                 }
597                 uint32_t vv = StringHelper::Utf8ToU32String(oct);
598                 if (vv < base::utf_helper::DECODE_SECOND_FACTOR) {
599                     if (!IsInURISet(vv)) {
600                         sStr = StringHelper::Utf16ToU16String(reinterpret_cast<uint16_t *>(&vv), 1);
601                     } else {
602                         auto substr = EcmaStringAccessor::FastSubString(
603                             thread->GetEcmaVM(), str, start, static_cast<uint32_t>(k) - start + 1U);
604                         sStr = StringHelper::StringToU16string(
605                             EcmaStringAccessor(substr).ToStdString(StringConvertedUsage::LOGICOPERATION));
606                     }
607                 } else {
608                     uint16_t lv = (((vv - base::utf_helper::DECODE_SECOND_FACTOR) & BIT16_MASK) +
609                         base::utf_helper::DECODE_TRAIL_LOW);
610                     uint16_t hv = ((((vv - base::utf_helper::DECODE_SECOND_FACTOR) >> 10U) & BIT16_MASK) +  // NOLINT
611                         base::utf_helper::DECODE_LEAD_LOW);  // 10: means shift left by 10 digits
612                     sStr = StringHelper::Append(StringHelper::Utf16ToU16String(&hv, 1),
613                                                 StringHelper::Utf16ToU16String(&lv, 1));
614                 }
615             }
616         }
617         // e. Let R be a new String value computed by concatenating the previous value of R and S.
618         // f. Increase k by 1.
619         resStr.append(sStr);
620         k++;
621     }
622 }
623 
PrintString(JSThread * thread,EcmaString * string)624 void BuiltinsGlobal::PrintString([[maybe_unused]] JSThread *thread, EcmaString *string)
625 {
626     if (string == nullptr) {
627         return;
628     }
629     BUILTINS_API_TRACE(thread, Global, PrintString);
630     CString buffer = ConvertToString(string);
631     std::cout << buffer;
632 }
633 
PrintEntrypoint(EcmaRuntimeCallInfo * msg)634 JSTaggedValue BuiltinsGlobal::PrintEntrypoint(EcmaRuntimeCallInfo *msg)
635 {
636     if (msg == nullptr) {
637         return JSTaggedValue::Undefined();
638     }
639     JSThread *thread = msg->GetThread();
640     [[maybe_unused]] EcmaHandleScope handleScope(thread);
641     BUILTINS_API_TRACE(thread, Global, PrintEntryPoint);
642 
643     uint32_t numArgs = msg->GetArgsNumber();
644     for (uint32_t i = 0; i < numArgs; i++) {
645         JSHandle<EcmaString> stringContent = JSTaggedValue::ToString(thread, GetCallArg(msg, i));
646         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
647         PrintString(thread, *stringContent);
648 
649         if (i != numArgs - 1) {
650             std::cout << " ";
651         }
652     }
653     std::cout << std::endl;
654     return JSTaggedValue::Undefined();
655 }
656 
MarkModuleCollectable(EcmaRuntimeCallInfo * msg)657 JSTaggedValue BuiltinsGlobal::MarkModuleCollectable(EcmaRuntimeCallInfo *msg)
658 {
659     ASSERT(msg);
660     JSThread *thread = msg->GetThread();
661     [[maybe_unused]] EcmaHandleScope handleScope(thread);
662 
663     uint32_t numArgs = msg->GetArgsNumber();
664     if (numArgs != 1) {
665         LOG_FULL(ERROR) << "The number of parameters received by markModuleCollectable is incorrect.";
666         return JSTaggedValue::False();
667     }
668     JSHandle<JSTaggedValue> module = GetCallArg(msg, 0);
669     if (!module->IsModuleNamespace()) {
670         return JSTaggedValue::False();
671     }
672 
673     ModuleDeregister::ProcessModuleReference(thread, module);
674     return JSTaggedValue::True();
675 }
676 
CallJsBoundFunction(EcmaRuntimeCallInfo * msg)677 JSTaggedValue BuiltinsGlobal::CallJsBoundFunction(EcmaRuntimeCallInfo *msg)
678 {
679     JSThread *thread = msg->GetThread();
680     BUILTINS_API_TRACE(thread, Global, CallJsBoundFunction);
681     [[maybe_unused]] EcmaHandleScope handleScope(thread);
682     // msg contains jsfunc, this, arg1,...
683 
684     JSHandle<JSBoundFunction> boundFunc(GetConstructor(msg));
685     JSHandle<JSTaggedValue> thisObj(thread, boundFunc->GetBoundThis());
686     msg->SetThis(thisObj.GetTaggedValue());
687     return RuntimeStubs::CallBoundFunction(msg);
688 }
689 
CallJsProxy(EcmaRuntimeCallInfo * msg)690 JSTaggedValue BuiltinsGlobal::CallJsProxy(EcmaRuntimeCallInfo *msg)
691 {
692     JSThread *thread = msg->GetThread();
693     BUILTINS_API_TRACE(thread, Global, CallJsProxy);
694     [[maybe_unused]] EcmaHandleScope handleScope(thread);
695     // msg contains js_proxy, this, arg1,...
696     JSHandle<JSProxy> proxy(GetConstructor(msg));
697     if (!proxy->IsCallable()) {
698         THROW_TYPE_ERROR_AND_RETURN(thread, "Proxy target is not callable", JSTaggedValue::Undefined());
699     }
700 
701     // Calling proxy directly should transfer 'undefined' as this
702     return JSProxy::CallInternal(msg);
703 }
704 
705 #if ECMASCRIPT_ENABLE_RUNTIME_STAT
StartRuntimeStat(EcmaRuntimeCallInfo * msg)706 JSTaggedValue BuiltinsGlobal::StartRuntimeStat(EcmaRuntimeCallInfo *msg)
707 {
708     JSThread *thread = msg->GetThread();
709     BUILTINS_API_TRACE(thread, Global, StartRuntimeStat);
710     [[maybe_unused]] EcmaHandleScope handleScope(thread);
711     // start vm runtime stat statistic
712     thread->GetCurrentEcmaContext()->SetRuntimeStatEnable(true);
713     return JSTaggedValue::Undefined();
714 }
715 
StopRuntimeStat(EcmaRuntimeCallInfo * msg)716 JSTaggedValue BuiltinsGlobal::StopRuntimeStat(EcmaRuntimeCallInfo *msg)
717 {
718     JSThread *thread = msg->GetThread();
719     BUILTINS_API_TRACE(thread, Global, StopRuntimeStat);
720     [[maybe_unused]] EcmaHandleScope handleScope(thread);
721     // start vm runtime stat statistic
722     thread->GetCurrentEcmaContext()->SetRuntimeStatEnable(false);
723     return JSTaggedValue::Undefined();
724 }
725 #endif
726 
727 #if ECMASCRIPT_ENABLE_OPT_CODE_PROFILER
PrintOptStat(EcmaRuntimeCallInfo * msg)728 JSTaggedValue BuiltinsGlobal::PrintOptStat(EcmaRuntimeCallInfo *msg)
729 {
730     JSThread *thread = msg->GetThread();
731     BUILTINS_API_TRACE(thread, Global, PrintOptStat);
732     [[maybe_unused]] EcmaHandleScope handleScope(thread);
733     // start vm runtime stat statistic
734     thread->GetCurrentEcmaContext()->PrintOptStat();
735     return JSTaggedValue::Undefined();
736 }
737 #endif
738 
739 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
PrintFunctionCallStat(EcmaRuntimeCallInfo * msg)740 JSTaggedValue BuiltinsGlobal::PrintFunctionCallStat(EcmaRuntimeCallInfo *msg)
741 {
742     JSThread *thread = msg->GetThread();
743     BUILTINS_API_TRACE(thread, Global, PrintFunctionCallStat);
744     [[maybe_unused]] EcmaHandleScope handleScope(thread);
745     // start vm runtime stat statistic
746     thread->GetEcmaVM()->DumpCallTimeInfo();
747     return JSTaggedValue::Undefined();
748 }
749 #endif
750 
751 // B.2.1.1 escape ( string )
Escape(EcmaRuntimeCallInfo * msg)752 JSTaggedValue BuiltinsGlobal::Escape(EcmaRuntimeCallInfo *msg)
753 {
754     ASSERT(msg);
755     JSThread *thread = msg->GetThread();
756     BUILTINS_API_TRACE(thread, Global, Escape);
757     [[maybe_unused]] EcmaHandleScope handleScope(thread);
758     // 1. Set string to ? ToString(string).
759     JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
760     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
761     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
762     // 2. Let len be the length of string.
763     uint32_t len = EcmaStringAccessor(string).GetLength();
764     // 3. Let R be the empty String.
765     std::u16string r;
766     // 4. Let unescapedSet be the string-concatenation of the ASCII word characters and "@*+-./".
767     // 5. Let k be 0.
768     uint32_t k = 0;
769     // 6. Repeat, while k < len,
770     //   a. Let C be the code unit at index k within string.
771     //   b. If unescapedSet contains C, then
772     //        i. Let S be C.
773     //   c. Else,
774     //        i. Let n be the numeric value of C.
775     //        ii. If n < 256, then
776     //          1. Let hex be the String representation of n, formatted as an uppercase hexadecimal number.
777     //          2. Let S be the string-concatenation of "%" and StringPad(hex, 2, "0", start).
778     //        iii. Else,
779     //          1. Let hex be the String representation of n, formatted as an uppercase hexadecimal number.
780     //          2. Let S be the string-concatenation of "%u" and StringPad(hex, 4, "0", start).
781     //    d. Set R to the string-concatenation of R and S.
782     //    e. Set k to k + 1.
783     while (k < len) {
784         uint16_t c = EcmaStringAccessor(string).Get(k);
785         if (c < std::numeric_limits<int8_t>::max() && ESCAPE_BIT_MAP[c] == 1) {
786             r.push_back(c);
787         } else {
788             r.push_back('%');
789             if (c <= std::numeric_limits<uint8_t>::max()) {
790                 r.push_back(ESCAPE_HEX_TO_CHAR[(c >> ESCAPE_HEX_BIT4) & ESCAPE_HEX_MASK]);
791                 r.push_back(ESCAPE_HEX_TO_CHAR[c & ESCAPE_HEX_MASK]);
792             } else {
793                 r.push_back('u');
794                 r.push_back(ESCAPE_HEX_TO_CHAR[(c >> ESCAPE_HEX_BIT12) & ESCAPE_HEX_MASK]);
795                 r.push_back(ESCAPE_HEX_TO_CHAR[(c >> ESCAPE_HEX_BIT8) & ESCAPE_HEX_MASK]);
796                 r.push_back(ESCAPE_HEX_TO_CHAR[(c >> ESCAPE_HEX_BIT4) & ESCAPE_HEX_MASK]);
797                 r.push_back(ESCAPE_HEX_TO_CHAR[c & ESCAPE_HEX_MASK]);
798             }
799         }
800         ++k;
801     }
802     // 7. Return R.
803     auto *returnData = reinterpret_cast<uint16_t *>(r.data());
804     uint32_t retSize = r.size();
805     return factory->NewFromUtf16Literal(returnData, retSize).GetTaggedValue();
806 }
807 
808 // B.2.1.2 unescape ( string )
Unescape(EcmaRuntimeCallInfo * msg)809 JSTaggedValue BuiltinsGlobal::Unescape(EcmaRuntimeCallInfo *msg)
810 {
811     ASSERT(msg);
812     JSThread *thread = msg->GetThread();
813     BUILTINS_API_TRACE(thread, Global, Unescape);
814     [[maybe_unused]] EcmaHandleScope handleScope(thread);
815     // 1. Set string to ? ToString(string).
816     JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
817     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
818     // 2. Let len be the length of string.
819     uint32_t len = EcmaStringAccessor(string).GetLength();
820     // 3. Let R be the empty String.
821     EcmaVM *vm = thread->GetEcmaVM();
822     ObjectFactory *factory = vm->GetFactory();
823     std::u16string r;
824     // 4. Let k be 0.
825     uint32_t k = 0;
826     // 5. Repeat, while k < len,
827     //   a. Let C be the code unit at index k within string.
828     //   b. If C is the code unit 0x0025 (PERCENT SIGN), then
829     //     i. Let hexDigits be the empty String.
830     //     ii. Let optionalAdvance be 0.
831     //     iii. If k + 5 < len and the code unit at index k + 1 within string is the code unit
832     //          0x0075 (LATIN SMALL LETTER U), then
833     //       1. Set hexDigits to the substring of string from k + 2 to k + 6.
834     //       2. Set optionalAdvance to 5.
835     //     iv. Else if k + 3 ≤ len, then
836     //       1. Set hexDigits to the substring of string from k + 1 to k + 3.
837     //       2. Set optionalAdvance to 2.
838     //     v. Let parseResult be ParseText(StringToCodePoints(hexDigits), HexDigits[~Sep]).
839     //     vi. If parseResult is a Parse Node, then
840     //       1. Let n be the MV of parseResult.
841     //       2. Set C to the code unit whose numeric value is n.
842     //       3. Set k to k + optionalAdvance.
843     //   c. Set R to the string-concatenation of R and C.
844     //   d. Set k to k + 1.
845     while (k < len) {
846         uint16_t c = EcmaStringAccessor(string).Get(k);
847         if (c == '%') {
848             uint16_t c1 = EcmaStringAccessor(string).Get(k + 1);
849             if (k + ESCAPE_CHAR_OFFSET5 < len && c1 == 'u') {
850                 uint16_t c2 = EcmaStringAccessor(string).Get(k + ESCAPE_CHAR_OFFSET2);
851                 uint16_t c3 = EcmaStringAccessor(string).Get(k + ESCAPE_CHAR_OFFSET3);
852                 uint16_t c4 = EcmaStringAccessor(string).Get(k + ESCAPE_CHAR_OFFSET4);
853                 uint16_t c5 = EcmaStringAccessor(string).Get(k + ESCAPE_CHAR_OFFSET5);
854                 bool c2IsHexDigits = IsHexDigits(c2);
855                 bool c3IsHexDigits = IsHexDigits(c3);
856                 bool c4IsHexDigits = IsHexDigits(c4);
857                 bool c5IsHexDigits = IsHexDigits(c5);
858                 bool isHexDigits = c2IsHexDigits && c3IsHexDigits && c4IsHexDigits && c5IsHexDigits;
859                 if (isHexDigits) {
860                     c = ESCAPE_CHAR_TO_HEX[c2];
861                     c = (c << ESCAPE_HEX_BIT4) | ESCAPE_CHAR_TO_HEX[c3];
862                     c = (c << ESCAPE_HEX_BIT4) | ESCAPE_CHAR_TO_HEX[c4];
863                     c = (c << ESCAPE_HEX_BIT4) | ESCAPE_CHAR_TO_HEX[c5];
864                     k = k + ESCAPE_CHAR_OFFSET5;
865                 }
866             } else if (k + ESCAPE_CHAR_OFFSET3 <= len) {
867                 uint16_t c2 = EcmaStringAccessor(string).Get(k + ESCAPE_CHAR_OFFSET2);
868                 bool c1IsHexDigits = IsHexDigits(c1);
869                 bool c2IsHexDigits = IsHexDigits(c2);
870                 bool isHexDigits = c1IsHexDigits && c2IsHexDigits;
871                 if (isHexDigits) {
872                     c = ESCAPE_CHAR_TO_HEX[c1];
873                     c = (c << ESCAPE_HEX_BIT4) | ESCAPE_CHAR_TO_HEX[c2];
874                     k = k + ESCAPE_CHAR_OFFSET2;
875                 }
876             }
877         }
878         r.push_back(c);
879         ++k;
880     }
881     // 7. Return R.
882     auto *returnData = reinterpret_cast<uint16_t *>(r.data());
883     uint32_t retSize = r.size();
884     return factory->NewFromUtf16Literal(returnData, retSize).GetTaggedValue();
885 }
886 }  // namespace panda::ecmascript::builtins
887