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