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