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
32 namespace panda::ecmascript::builtins {
33 using NumberHelper = base::NumberHelper;
34 using StringHelper = base::StringHelper;
35 using GlobalError = containers::ContainerError;
36 // bitmap for "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" + "@*+-./"
37 constexpr 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};
46 constexpr 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 };
49 constexpr 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 };
59 constexpr std::uint8_t ESCAPE_HEX_MASK = 0xf;
60 constexpr std::uint8_t ESCAPE_HEX_BIT4 = 4;
61 constexpr std::uint8_t ESCAPE_HEX_BIT8 = 8;
62 constexpr std::uint8_t ESCAPE_HEX_BIT12 = 12;
63 constexpr std::uint8_t ESCAPE_CHAR_OFFSET2 = 2;
64 constexpr std::uint8_t ESCAPE_CHAR_OFFSET3 = 3;
65 constexpr std::uint8_t ESCAPE_CHAR_OFFSET4 = 4;
66 constexpr std::uint8_t ESCAPE_CHAR_OFFSET5 = 5;
67 constexpr std::uint16_t CHAR16_LETTER_NULL = u'\0';
68
69 // 18.2.1
NotSupportEval(EcmaRuntimeCallInfo *msg)70 JSTaggedValue 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
IsFinite(EcmaRuntimeCallInfo *msg)79 JSTaggedValue 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
IsNaN(EcmaRuntimeCallInfo *msg)98 JSTaggedValue 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
IsUnescapedURI(uint16_t ch)117 bool 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
IsInUnescapedURISet(uint16_t ch)125 bool BuiltinsGlobal::IsInUnescapedURISet(uint16_t ch)
126 {
127 if (ch == '#') {
128 return true;
129 }
130 return IsUnescapedURI(ch) || IsReservedURI(ch);
131 }
132
IsInReservedURISet(uint16_t ch)133 bool BuiltinsGlobal::IsInReservedURISet(uint16_t ch)
134 {
135 if (ch == '#') {
136 return true;
137 }
138 return IsReservedURI(ch);
139 }
140
IsReservedURI(uint16_t ch)141 bool 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
IsInMarkURISet(uint16_t ch)148 bool 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
IsHexDigits(uint16_t ch)155 bool 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
DecodeURI(EcmaRuntimeCallInfo *msg)161 JSTaggedValue 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
EncodeURI(EcmaRuntimeCallInfo *msg)177 JSTaggedValue 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
DecodeURIComponent(EcmaRuntimeCallInfo *msg)194 JSTaggedValue 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
EncodeURIComponent(EcmaRuntimeCallInfo *msg)210 JSTaggedValue 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
Encode(JSThread *thread, const JSHandle<EcmaString> &str, judgURIFunc IsInURISet)227 JSTaggedValue 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
GetValueFromTwoHex(uint16_t front, uint16_t behind)320 uint8_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
GetValueFromHexString(const JSHandle<EcmaString> &string)331 uint16_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 )
StringPad(JSThread *thread, const JSHandle<EcmaString> &source, uint32_t maxLength, const JSHandle<EcmaString> &fillString, Placement placement)347 EcmaString *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 )
UTF16SurrogatePairToCodePoint(uint16_t lead, uint16_t trail)386 uint16_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 )
StringToCodePoints(JSThread *thread, const JSHandle<EcmaString> &string)397 EcmaString *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
Decode(JSThread *thread, const JSHandle<EcmaString> &str, judgURIFunc IsInURISet)452 JSTaggedValue 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
HandleSingleByteCharacter(JSThread *thread, uint8_t &bb, const JSHandle<EcmaString> &str, uint32_t &start, int32_t &k, std::u16string &sStr, judgURIFunc IsInURISet)506 void 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
DecodePercentEncoding(JSThread *thread, const JSHandle<EcmaString> &str, int32_t &k, judgURIFunc IsInURISet, int32_t strLen, std::u16string &sStr)522 JSTaggedValue 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
DecodePercentEncoding(JSThread *thread, int32_t &n, int32_t &k, const JSHandle<EcmaString> &str, uint8_t &bb, std::vector<uint8_t> &oct)595 JSTaggedValue 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
UTF16EncodeCodePoint(JSThread *thread, judgURIFunc IsInURISet, const std::vector<uint8_t> &oct, const JSHandle<EcmaString> &str, uint32_t &start, int32_t &k, std::u16string &sStr)631 JSTaggedValue 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
PrintString([[maybe_unused]] JSThread *thread, EcmaString *string)660 void 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
PrintEntrypoint(EcmaRuntimeCallInfo *msg)670 JSTaggedValue 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
MarkModuleCollectable(EcmaRuntimeCallInfo *msg)693 JSTaggedValue 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
LoadNativeModule(EcmaRuntimeCallInfo *msg)713 JSTaggedValue 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
CallJsBoundFunction(EcmaRuntimeCallInfo *msg)766 JSTaggedValue 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
CallJsProxy(EcmaRuntimeCallInfo *msg)779 JSTaggedValue 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
StartRuntimeStat(EcmaRuntimeCallInfo *msg)795 JSTaggedValue 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
StopRuntimeStat(EcmaRuntimeCallInfo *msg)805 JSTaggedValue 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
PrintOptStat(EcmaRuntimeCallInfo *msg)817 JSTaggedValue 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
PrintFunctionCallStat(EcmaRuntimeCallInfo *msg)829 JSTaggedValue 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 )
Escape(EcmaRuntimeCallInfo *msg)841 JSTaggedValue 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 )
Unescape(EcmaRuntimeCallInfo *msg)898 JSTaggedValue 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
GetCurrentModuleName(EcmaRuntimeCallInfo *msg)976 JSTaggedValue 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
GetCurrentBundleName(EcmaRuntimeCallInfo *msg)991 JSTaggedValue 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
IsSendable(EcmaRuntimeCallInfo *msg)1007 JSTaggedValue 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