• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/builtins/builtins_global.h"
17 
18 #include <random>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 #include "ecmascript/base/number_helper.h"
24 #include "ecmascript/base/string_helper.h"
25 #include "ecmascript/ecma_macros.h"
26 #include "ecmascript/js_function.h"
27 #include "ecmascript/mem/c_containers.h"
28 #include "ecmascript/module/js_module_deregister.h"
29 #include "ecmascript/stubs/runtime_stubs.h"
30 #include "ecmascript/tagged_array-inl.h"
31 
32 namespace panda::ecmascript::builtins {
33 using NumberHelper = base::NumberHelper;
34 using StringHelper = base::StringHelper;
35 
36 // 18.2.1
NotSupportEval(EcmaRuntimeCallInfo * msg)37 JSTaggedValue BuiltinsGlobal::NotSupportEval(EcmaRuntimeCallInfo *msg)
38 {
39     JSThread *thread = msg->GetThread();
40     BUILTINS_API_TRACE(thread, Global, NotSupportEval);
41     [[maybe_unused]] EcmaHandleScope handleScope(thread);
42     THROW_TYPE_ERROR_AND_RETURN(thread, "not support eval()", JSTaggedValue::Exception());
43 }
44 
45 // 18.2.2
IsFinite(EcmaRuntimeCallInfo * msg)46 JSTaggedValue BuiltinsGlobal::IsFinite(EcmaRuntimeCallInfo *msg)
47 {
48     ASSERT(msg);
49     JSThread *thread = msg->GetThread();
50     BUILTINS_API_TRACE(thread, Global, IsFinite);
51     [[maybe_unused]] EcmaHandleScope handleScope(thread);
52     JSHandle<JSTaggedValue> numberInput = GetCallArg(msg, 0);
53     // 1. Let num be ToNumber(number).
54     JSTaggedNumber number = JSTaggedValue::ToNumber(thread, numberInput);
55     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
56     // 3. If num is NaN, +Infinite, or -Infinite, return false.
57     // 4. Otherwise, return true.
58     if (std::isfinite(number.GetNumber())) {
59         return GetTaggedBoolean(true);
60     }
61     return GetTaggedBoolean(false);
62 }
63 
64 // 18.2.3
IsNaN(EcmaRuntimeCallInfo * msg)65 JSTaggedValue BuiltinsGlobal::IsNaN(EcmaRuntimeCallInfo *msg)
66 {
67     ASSERT(msg);
68     JSThread *thread = msg->GetThread();
69     BUILTINS_API_TRACE(thread, Global, IsNaN);
70     [[maybe_unused]] EcmaHandleScope handleScope(thread);
71     JSHandle<JSTaggedValue> numberInput = GetCallArg(msg, 0);
72     // 1. Let num be ToNumber(number).
73     JSTaggedNumber number = JSTaggedValue::ToNumber(thread, numberInput);
74     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
75 
76     // 3. If num is NaN, return true.
77     if (std::isnan(number.GetNumber())) {
78         return GetTaggedBoolean(true);
79     }
80     // 4. Otherwise, return false.
81     return GetTaggedBoolean(false);
82 }
83 
IsUnescapedURI(uint16_t ch)84 bool BuiltinsGlobal::IsUnescapedURI(uint16_t ch)
85 {
86     if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
87         return true;
88     }
89     return IsInMarkURISet(ch);
90 }
91 
IsInUnescapedURISet(uint16_t ch)92 bool BuiltinsGlobal::IsInUnescapedURISet(uint16_t ch)
93 {
94     if (ch == '#') {
95         return true;
96     }
97     return IsUnescapedURI(ch) || IsReservedURI(ch);
98 }
99 
IsInReservedURISet(uint16_t ch)100 bool BuiltinsGlobal::IsInReservedURISet(uint16_t ch)
101 {
102     if (ch == '#') {
103         return true;
104     }
105     return IsReservedURI(ch);
106 }
107 
IsReservedURI(uint16_t ch)108 bool BuiltinsGlobal::IsReservedURI(uint16_t ch)
109 {
110     std::u16string str(u";/?:@&=+$,");
111     std::u16string::size_type index = str.find(ch);
112     return (index != std::u16string::npos);
113 }
114 
IsInMarkURISet(uint16_t ch)115 bool BuiltinsGlobal::IsInMarkURISet(uint16_t ch)
116 {
117     std::u16string str(u"-_.!~*'()");
118     std::u16string::size_type index = str.find(ch);
119     return (index != std::u16string::npos);
120 }
121 
IsHexDigits(uint16_t ch)122 bool BuiltinsGlobal::IsHexDigits(uint16_t ch)
123 {
124     return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
125 }
126 
127 // 18.2.6
DecodeURI(EcmaRuntimeCallInfo * msg)128 JSTaggedValue BuiltinsGlobal::DecodeURI(EcmaRuntimeCallInfo *msg)
129 {
130     ASSERT(msg);
131     JSThread *thread = msg->GetThread();
132     BUILTINS_API_TRACE(thread, Global, DecodeURI);
133     [[maybe_unused]] EcmaHandleScope handleScope(thread);
134     // 1. Let uriString be ToString(encodedURI).
135     // 2. ReturnIfAbrupt(uriString).
136     JSHandle<EcmaString> uriString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
137     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
138 
139     // 3. Let reservedURISet be a String containing one instance of each code unit valid in uriReserved plus "#".
140     // 4. Return Decode(uriString, reservedURISet).
141     return Decode(thread, uriString, IsInReservedURISet);
142 }
143 
EncodeURI(EcmaRuntimeCallInfo * msg)144 JSTaggedValue BuiltinsGlobal::EncodeURI(EcmaRuntimeCallInfo *msg)
145 {
146     ASSERT(msg);
147     JSThread *thread = msg->GetThread();
148     BUILTINS_API_TRACE(thread, Global, EncodeURI);
149     [[maybe_unused]] EcmaHandleScope handleScope(thread);
150     // 1. Let uriString be ToString(uri).
151     // 2. ReturnIfAbrupt(uriString).
152     JSHandle<EcmaString> uriString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
153     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
154 
155     // 3. Let unescapedURISet be a String containing one instance of
156     //    each code unit valid in uriReserved and uriUnescaped plus "#".
157     // 4. Return Encode(uriString, unescapedURISet).
158     return Encode(thread, uriString, IsInUnescapedURISet);
159 }
160 
DecodeURIComponent(EcmaRuntimeCallInfo * msg)161 JSTaggedValue BuiltinsGlobal::DecodeURIComponent(EcmaRuntimeCallInfo *msg)
162 {
163     ASSERT(msg);
164     JSThread *thread = msg->GetThread();
165     BUILTINS_API_TRACE(thread, Global, DecodeURIComponent);
166     [[maybe_unused]] EcmaHandleScope handleScope(thread);
167     // 1. Let componentString be ToString(encodedURIComponent).
168     // 2. ReturnIfAbrupt(componentString).
169     JSHandle<EcmaString> componentString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
170     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
171 
172     // 3. Let reservedURIComponentSet be the empty String.
173     // 4. Return Decode(componentString, reservedURIComponentSet).
174     return Decode(thread, componentString, []([[maybe_unused]] uint16_t unused) { return false; });
175 }
176 
EncodeURIComponent(EcmaRuntimeCallInfo * msg)177 JSTaggedValue BuiltinsGlobal::EncodeURIComponent(EcmaRuntimeCallInfo *msg)
178 {
179     ASSERT(msg);
180     JSThread *thread = msg->GetThread();
181     BUILTINS_API_TRACE(thread, Global, EncodeURIComponent);
182     [[maybe_unused]] EcmaHandleScope handleScope(thread);
183     // 1. Let componentString be ToString(uriComponent).
184     // 2. ReturnIfAbrupt(componentString).
185     JSHandle<EcmaString> componentString = JSTaggedValue::ToString(thread, GetCallArg(msg, 0));
186     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
187 
188     // 3. Let unescapedURIComponentSet be a String containing one instance of each code unit valid in uriUnescaped.
189     // 4. Return Encode(componentString, unescapedURIComponentSet).
190     return Encode(thread, componentString, IsUnescapedURI);
191 }
192 
193 // Runtime Semantics
Encode(JSThread * thread,const JSHandle<EcmaString> & str,judgURIFunc IsInURISet)194 JSTaggedValue BuiltinsGlobal::Encode(JSThread *thread, const JSHandle<EcmaString> &str, judgURIFunc IsInURISet)
195 {
196     BUILTINS_API_TRACE(thread, Global, Encode);
197     // 1. Let strLen be the number of code units in string.
198     uint32_t strLen = EcmaStringAccessor(str).GetLength();
199     // 2. Let R be the empty String.
200     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
201     std::u16string resStr;
202 
203     // 3. Let k be 0.
204     // 4. Repeat
205     uint32_t k = 0;
206     while (true) {
207         // a. If k equals strLen, return R.
208         if (k == strLen) {
209             auto *uint16tData = reinterpret_cast<uint16_t *>(resStr.data());
210             uint32_t resSize = resStr.size();
211             return factory->NewFromUtf16Literal(uint16tData, resSize).GetTaggedValue();
212         }
213 
214         // b. Let C be the code unit at index k within string.
215         // c. If C is in unescapedSet, then
216         //   i. Let S be a String containing only the code unit C.
217         //   ii. Let R be a new String value computed by concatenating the previous value of R and S.
218         // d. Else C is not in unescapedSet,
219         uint16_t cc = EcmaStringAccessor(str).Get(k);
220         if (IsInURISet(cc)) {
221             std::u16string sStr = StringHelper::Utf16ToU16String(&cc, 1);
222             resStr.append(sStr);
223         } else {
224             // i. If the code unit value of C is not less than 0xDC00 and not greater than 0xDFFF,
225             //    throw a URIError exception.
226             if (cc >= base::utf_helper::DECODE_TRAIL_LOW && cc <= base::utf_helper::DECODE_TRAIL_HIGH) {
227                 THROW_URI_ERROR_AND_RETURN(thread, "EncodeURI: The format of the URI to be parsed is incorrect",
228                                            JSTaggedValue::Exception());
229             }
230 
231             // ii. If the code unit value of C is less than 0xD800 or greater than 0xDBFF, then
232             //    1. Let V be the code unit value of C.
233             // iii. Else,
234             //    1. Increase k by 1.
235             //    2. If k equals strLen, throw a URIError exception.
236             //    3. Let kChar be the code unit value of the code unit at index k within string.
237             //    4. If kChar is less than 0xDC00 or greater than 0xDFFF, throw a URIError exception.
238             //    5. Let V be UTF16Decode(C, kChar).
239             uint32_t vv;
240             if (cc < base::utf_helper::DECODE_LEAD_LOW || cc > base::utf_helper::DECODE_LEAD_HIGH) {
241                 vv = cc;
242             } else {
243                 k++;
244                 if (k == strLen) {
245                     THROW_URI_ERROR_AND_RETURN(thread, "k is invalid", JSTaggedValue::Exception());
246                 }
247                 uint16_t kc = EcmaStringAccessor(str).Get(k);
248                 if (kc < base::utf_helper::DECODE_TRAIL_LOW || kc > base::utf_helper::DECODE_TRAIL_HIGH) {
249                     THROW_URI_ERROR_AND_RETURN(thread, "EncodeURI: The format of the URI to be parsed is incorrect",
250                                                JSTaggedValue::Exception());
251                 }
252                 vv = base::utf_helper::UTF16Decode(cc, kc);
253             }
254 
255             // iv. Let Octets be the array of octets resulting by applying the UTF-8 transformation to V,
256             //     and let L be the array size.
257             // v. Let j be 0.
258             // vi. Repeat, while j < L
259             //    1. Let jOctet be the value at index j within Octets.
260             //    2. Let S be a String containing three code units "%XY" where XY are two uppercase hexadecimal
261             //       digits encoding the value of jOctet.
262             //    3. Let R be a new String value computed by concatenating the previous value of R and S.
263             //    4. Increase j by 1.
264             std::string oct = StringHelper::Utf32ToString(vv);
265             std::string hexStr("0123456789ABCDEF");
266 
267             uint32_t length = oct.length();
268             std::stringstream tmpStr;
269             for (uint32_t j = 0; j < length; j++) {
270                 uint8_t joct = static_cast<uint8_t>(oct.at(j));
271                 tmpStr << '%' << hexStr.at((joct >> 4U) & BIT_MASK)  // NOLINT
272                        << hexStr.at(joct & BIT_MASK);                // 4: means shift right by 4 digits
273             }
274             resStr.append(StringHelper::StringToU16string(tmpStr.str()));
275         }
276 
277         // e. Increase k by 1.
278         k++;
279     }
280 }
281 
GetValueFromTwoHex(uint16_t front,uint16_t behind)282 uint8_t BuiltinsGlobal::GetValueFromTwoHex(uint16_t front, uint16_t behind)
283 {
284     ASSERT(IsHexDigits(front) && IsHexDigits(behind));
285     std::u16string hexString(u"0123456789ABCDEF");
286 
287     size_t idxf = StringHelper::FindFromU16ToUpper(hexString, &front);
288     size_t idxb = StringHelper::FindFromU16ToUpper(hexString, &behind);
289     uint8_t res = ((idxf << 4U) | idxb) & BIT_MASK_FF;  // NOLINT 4: means shift left by 4 digits
290     return res;
291 }
292 
293 // Runtime Semantics
Decode(JSThread * thread,const JSHandle<EcmaString> & str,judgURIFunc IsInURISet)294 JSTaggedValue BuiltinsGlobal::Decode(JSThread *thread, const JSHandle<EcmaString> &str, judgURIFunc IsInURISet)
295 {
296     BUILTINS_API_TRACE(thread, Global, Decode);
297     // 1. Let strLen be the number of code units in string.
298     int32_t strLen = static_cast<int32_t>(EcmaStringAccessor(str).GetLength());
299     // 2. Let R be the empty String.
300     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
301     std::u16string resStr;
302 
303     // 3. Let k be 0.
304     // 4. Repeat
305     int32_t k = 0;
306     while (true) {
307         // a. If k equals strLen, return R.
308         if (k == strLen) {
309             auto *uint16tData = reinterpret_cast<uint16_t *>(resStr.data());
310             uint32_t resSize = resStr.size();
311             return factory->NewFromUtf16Literal(uint16tData, resSize).GetTaggedValue();
312         }
313 
314         // b. Let C be the code unit at index k within string.
315         // c. If C is not "%", then
316         //    i. Let S be the String containing only the code unit C.
317         // d. Else C is "%",
318         //   i. Let start be k.
319         //   iv. Let B be the 8-bit value represented by the two hexadecimal digits at index (k + 1) and (k + 2).
320         //   v. Increase k by 2.
321         //   vi. If the most significant bit in B is 0, then
322         //      1. Let C be the code unit with code unit value B.
323         //      2. If C is not in reservedSet, then
324         //         a. Let S be the String containing only the code unit C.
325         //      3. Else C is in reservedSet,
326         //         a. Let S be the substring of string from index start to index k inclusive.
327         uint16_t cc = EcmaStringAccessor(str).Get(k);
328         std::u16string sStr;
329         if (cc != '%') {
330             if (cc == 0 && strLen == 1) {
331                 JSHandle<EcmaString> tmpEcmaString = factory->NewFromUtf16Literal(&cc, 1);
332                 return tmpEcmaString.GetTaggedValue();
333             }
334             sStr = StringHelper::Utf16ToU16String(&cc, 1);
335         } else {
336             [[maybe_unused]] uint32_t start = static_cast<uint32_t>(k);
337 
338             // ii. If k + 2 is greater than or equal to strLen, throw a URIError exception.
339             // iii. If the code units at index (k+1) and (k + 2) within string do not represent hexadecimal digits,
340             //      throw a URIError exception.
341             if ((k + 2) >= strLen) {  // 2: means plus 2
342                 THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
343                                            JSTaggedValue::Exception());
344             }
345             if (!(IsHexDigits(EcmaStringAccessor(str).Get(k + 1)) &&
346                 IsHexDigits(EcmaStringAccessor(str).Get(k + 2)))) {  // 2: means plus 2
347                 THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
348                                            JSTaggedValue::Exception());
349             }
350 
351             uint16_t frontChar = EcmaStringAccessor(str).Get(k + 1);
352             uint16_t behindChar = EcmaStringAccessor(str).Get(k + 2);  // 2: means plus 2
353             uint8_t bb = GetValueFromTwoHex(frontChar, behindChar);
354             k += 2;  // 2: means plus 2
355             if ((bb & BIT_MASK_ONE) == 0) {
356                 if (!IsInURISet(bb)) {
357                     sStr = StringHelper::Utf8ToU16String(&bb, 1);
358                 } else {
359                     auto substr = EcmaStringAccessor::FastSubString(
360                         thread->GetEcmaVM(), str, start, static_cast<uint32_t>(k) - start + 1U);
361                     sStr = StringHelper::StringToU16string(
362                         EcmaStringAccessor(substr).ToStdString(StringConvertedUsage::LOGICOPERATION));
363                 }
364             } else {
365                 // vii. Else the most significant bit in B is 1,
366                 //   1. Let n be the smallest nonnegative integer such that (B << n) & 0x80 is equal to 0.
367                 //   3. Let Octets be an array of 8-bit integers of size n.
368                 //   4. Put B into Octets at index 0.
369                 //   6. Let j be 1.
370                 //   7. Repeat, while j < n
371                 //     a. Increase k by 1.
372                 //     d. Let B be the 8-bit value represented by the two hexadecimal digits at
373                 //        index (k + 1) and (k + 2).
374                 //     f. Increase k by 2.
375                 //     g. Put B into Octets at index j.
376                 //     h. Increase j by 1.
377                 //   9. If V < 0x10000, then
378                 //     a. Let C be the code unit V.
379                 //     b. If C is not in reservedSet, then
380                 //        i. Let S be the String containing only the code unit C.
381                 //     c. Else C is in reservedSet,
382                 //        i. Let S be the substring of string from index start to index k inclusive.
383                 //   10. Else V ≥ 0x10000,
384                 //     a. Let L be (((V – 0x10000) & 0x3FF) + 0xDC00).
385                 //     b. Let H be ((((V – 0x10000) >> 10) & 0x3FF) + 0xD800).
386                 //     c. Let S be the String containing the two code units H and L.
387                 int32_t n = 0;
388                 while ((((static_cast<uint32_t>(bb) << static_cast<uint32_t>(n)) & BIT_MASK_ONE) != 0)) {
389                     n++;
390                     if (n > 4) { // 4 : 4 means less than 4
391                         break;
392                     }
393                 }
394                 // 2. If n equals 1 or n is greater than 4, throw a URIError exception.
395                 if ((n == 1) || (n > 4)) {  // 4: means greater than 4
396                     THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
397                                                JSTaggedValue::Exception());
398                 }
399 
400                 std::vector<uint8_t> oct = {bb};
401 
402                 // 5. If k + (3 × (n – 1)) is greater than or equal to strLen, throw a URIError exception.
403                 if (k + (3 * (n - 1)) >= strLen) {  // 3: means multiply by 3
404                     THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
405                                                JSTaggedValue::Exception());
406                 }
407                 int32_t j = 1;
408                 while (j < n) {
409                     k++;
410                     uint16_t codeUnit = EcmaStringAccessor(str).Get(k);
411                     // b. If the code unit at index k within string is not "%", throw a URIError exception.
412                     // c. If the code units at index (k +1) and (k + 2) within string do not represent hexadecimal
413                     //    digits, throw a URIError exception.
414                     if (!(codeUnit == '%')) {
415                         THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
416                                                    JSTaggedValue::Exception());
417                     }
418                     if (!(IsHexDigits(EcmaStringAccessor(str).Get(k + 1)) &&
419                         IsHexDigits(EcmaStringAccessor(str).Get(k + 2)))) {  // 2: means plus 2
420                         THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
421                                                    JSTaggedValue::Exception());
422                     }
423 
424                     uint16_t frontChart = EcmaStringAccessor(str).Get(k + 1);
425                     uint16_t behindChart = EcmaStringAccessor(str).Get(k + 2);  // 2: means plus 2
426                     bb = GetValueFromTwoHex(frontChart, behindChart);
427                     // e. If the two most significant bits in B are not 10, throw a URIError exception.
428                     if (!((bb & BIT_MASK_TWO) == BIT_MASK_ONE)) {
429                         THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
430                                                    JSTaggedValue::Exception());
431                     }
432 
433                     k += 2;  // 2: means plus 2
434                     oct.push_back(bb);
435                     j++;
436                 }
437 
438                 // 8. Let V be the value obtained by applying the UTF-8 transformation to Octets, that is,
439                 //     from an array of octets into a 21-bit value. If Octets does not contain a valid UTF-8 encoding of
440                 //     a Unicode code point throw a URIError exception.
441                 if (!base::utf_helper::IsValidUTF8(oct)) {
442                     THROW_URI_ERROR_AND_RETURN(thread, "DecodeURI: The format of the URI to be parsed is incorrect",
443                                                JSTaggedValue::Exception());
444                 }
445                 uint32_t vv = StringHelper::Utf8ToU32String(oct);
446                 if (vv < base::utf_helper::DECODE_SECOND_FACTOR) {
447                     if (!IsInURISet(vv)) {
448                         sStr = StringHelper::Utf16ToU16String(reinterpret_cast<uint16_t *>(&vv), 1);
449                     } else {
450                         auto substr = EcmaStringAccessor::FastSubString(
451                             thread->GetEcmaVM(), str, start, static_cast<uint32_t>(k) - start + 1U);
452                         sStr = StringHelper::StringToU16string(
453                             EcmaStringAccessor(substr).ToStdString(StringConvertedUsage::LOGICOPERATION));
454                     }
455                 } else {
456                     uint16_t lv = (((vv - base::utf_helper::DECODE_SECOND_FACTOR) & BIT16_MASK) +
457                         base::utf_helper::DECODE_TRAIL_LOW);
458                     uint16_t hv = ((((vv - base::utf_helper::DECODE_SECOND_FACTOR) >> 10U) & BIT16_MASK) +  // NOLINT
459                         base::utf_helper::DECODE_LEAD_LOW);  // 10: means shift left by 10 digits
460                     sStr = StringHelper::Append(StringHelper::Utf16ToU16String(&hv, 1),
461                                                 StringHelper::Utf16ToU16String(&lv, 1));
462                 }
463             }
464         }
465         // e. Let R be a new String value computed by concatenating the previous value of R and S.
466         // f. Increase k by 1.
467         resStr.append(sStr);
468         k++;
469     }
470 }
471 
PrintString(JSThread * thread,EcmaString * string)472 void BuiltinsGlobal::PrintString([[maybe_unused]] JSThread *thread, EcmaString *string)
473 {
474     if (string == nullptr) {
475         return;
476     }
477     BUILTINS_API_TRACE(thread, Global, PrintString);
478     CString buffer = ConvertToString(string);
479     std::cout << buffer;
480 }
481 
PrintEntrypoint(EcmaRuntimeCallInfo * msg)482 JSTaggedValue BuiltinsGlobal::PrintEntrypoint(EcmaRuntimeCallInfo *msg)
483 {
484     if (msg == nullptr) {
485         return JSTaggedValue::Undefined();
486     }
487     JSThread *thread = msg->GetThread();
488     [[maybe_unused]] EcmaHandleScope handleScope(thread);
489     BUILTINS_API_TRACE(thread, Global, PrintEntryPoint);
490 
491     uint32_t numArgs = msg->GetArgsNumber();
492     for (uint32_t i = 0; i < numArgs; i++) {
493         JSHandle<EcmaString> stringContent = JSTaggedValue::ToString(thread, GetCallArg(msg, i));
494         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
495         PrintString(thread, *stringContent);
496 
497         if (i != numArgs - 1) {
498             std::cout << " ";
499         }
500     }
501     std::cout << std::endl;
502     return JSTaggedValue::Undefined();
503 }
504 
MarkModuleCollectable(EcmaRuntimeCallInfo * msg)505 JSTaggedValue BuiltinsGlobal::MarkModuleCollectable(EcmaRuntimeCallInfo *msg)
506 {
507     ASSERT(msg);
508     JSThread *thread = msg->GetThread();
509     [[maybe_unused]] EcmaHandleScope handleScope(thread);
510 
511     uint32_t numArgs = msg->GetArgsNumber();
512     if (numArgs != 1) {
513         LOG_FULL(ERROR) << "The number of parameters received by markModuleCollectable is incorrect.";
514         return JSTaggedValue::False();
515     }
516     JSHandle<JSTaggedValue> module = GetCallArg(msg, 0);
517     if (!module->IsModuleNamespace()) {
518         return JSTaggedValue::False();
519     }
520 
521     ModuleDeregister::ProcessModuleReference(thread, module);
522     return JSTaggedValue::True();
523 }
524 
CallJsBoundFunction(EcmaRuntimeCallInfo * msg)525 JSTaggedValue BuiltinsGlobal::CallJsBoundFunction(EcmaRuntimeCallInfo *msg)
526 {
527     JSThread *thread = msg->GetThread();
528     BUILTINS_API_TRACE(thread, Global, CallJsBoundFunction);
529     [[maybe_unused]] EcmaHandleScope handleScope(thread);
530     // msg contains jsfunc, this, arg1,...
531 
532     JSHandle<JSBoundFunction> boundFunc(GetConstructor(msg));
533     JSHandle<JSTaggedValue> thisObj(thread, boundFunc->GetBoundThis());
534     msg->SetThis(thisObj.GetTaggedValue());
535     return RuntimeStubs::CallBoundFunction(msg);
536 }
537 
CallJsProxy(EcmaRuntimeCallInfo * msg)538 JSTaggedValue BuiltinsGlobal::CallJsProxy(EcmaRuntimeCallInfo *msg)
539 {
540     JSThread *thread = msg->GetThread();
541     BUILTINS_API_TRACE(thread, Global, CallJsProxy);
542     [[maybe_unused]] EcmaHandleScope handleScope(thread);
543     // msg contains js_proxy, this, arg1,...
544     JSHandle<JSProxy> proxy(GetConstructor(msg));
545     if (!proxy->IsCallable()) {
546         THROW_TYPE_ERROR_AND_RETURN(thread, "Proxy target is not callable", JSTaggedValue::Undefined());
547     }
548 
549     // Calling proxy directly should transfer 'undefined' as this
550     return JSProxy::CallInternal(msg);
551 }
552 
553 #if ECMASCRIPT_ENABLE_RUNTIME_STAT
StartRuntimeStat(EcmaRuntimeCallInfo * msg)554 JSTaggedValue BuiltinsGlobal::StartRuntimeStat(EcmaRuntimeCallInfo *msg)
555 {
556     JSThread *thread = msg->GetThread();
557     BUILTINS_API_TRACE(thread, Global, StartRuntimeStat);
558     [[maybe_unused]] EcmaHandleScope handleScope(thread);
559     // start vm runtime stat statistic
560     thread->GetCurrentEcmaContext()->SetRuntimeStatEnable(true);
561     return JSTaggedValue::Undefined();
562 }
563 
StopRuntimeStat(EcmaRuntimeCallInfo * msg)564 JSTaggedValue BuiltinsGlobal::StopRuntimeStat(EcmaRuntimeCallInfo *msg)
565 {
566     JSThread *thread = msg->GetThread();
567     BUILTINS_API_TRACE(thread, Global, StopRuntimeStat);
568     [[maybe_unused]] EcmaHandleScope handleScope(thread);
569     // start vm runtime stat statistic
570     thread->GetCurrentEcmaContext()->SetRuntimeStatEnable(false);
571     return JSTaggedValue::Undefined();
572 }
573 #endif
574 
575 #if ECMASCRIPT_ENABLE_OPT_CODE_PROFILER
PrintOptStat(EcmaRuntimeCallInfo * msg)576 JSTaggedValue BuiltinsGlobal::PrintOptStat(EcmaRuntimeCallInfo *msg)
577 {
578     JSThread *thread = msg->GetThread();
579     BUILTINS_API_TRACE(thread, Global, PrintOptStat);
580     [[maybe_unused]] EcmaHandleScope handleScope(thread);
581     // start vm runtime stat statistic
582     thread->GetCurrentEcmaContext()->PrintOptStat();
583     return JSTaggedValue::Undefined();
584 }
585 #endif
586 
587 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
PrintFunctionCallStat(EcmaRuntimeCallInfo * msg)588 JSTaggedValue BuiltinsGlobal::PrintFunctionCallStat(EcmaRuntimeCallInfo *msg)
589 {
590     JSThread *thread = msg->GetThread();
591     BUILTINS_API_TRACE(thread, Global, PrintFunctionCallStat);
592     [[maybe_unused]] EcmaHandleScope handleScope(thread);
593     // start vm runtime stat statistic
594     thread->GetEcmaVM()->DumpCallTimeInfo();
595     return JSTaggedValue::Undefined();
596 }
597 #endif
598 }  // namespace panda::ecmascript::builtins
599