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