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