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