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/js_tagged_value.h"
17
18 #include "ecmascript/ecma_string-inl.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_api/js_api_arraylist.h"
22 #include "ecmascript/js_api/js_api_bitvector.h"
23 #include "ecmascript/js_api/js_api_deque.h"
24 #include "ecmascript/js_api/js_api_linked_list.h"
25 #include "ecmascript/js_api/js_api_list.h"
26 #include "ecmascript/js_api/js_api_plain_array.h"
27 #include "ecmascript/js_api/js_api_queue.h"
28 #include "ecmascript/js_api/js_api_stack.h"
29 #include "ecmascript/js_api/js_api_vector.h"
30 #include "ecmascript/js_date.h"
31 #include "ecmascript/js_primitive_ref.h"
32 #include "ecmascript/js_typed_array.h"
33 #include "ecmascript/message_string.h"
34 #include "ecmascript/shared_objects/js_shared_array.h"
35 #include "ecmascript/symbol_table.h"
36
37 namespace panda::ecmascript {
38
ToBoolean() const39 bool JSTaggedValue::ToBoolean() const
40 {
41 if (IsInt()) {
42 return GetInt() != 0;
43 }
44 if (IsDouble()) {
45 double d = GetDouble();
46 return !std::isnan(d) && d != 0;
47 }
48 switch (GetRawData()) {
49 case JSTaggedValue::VALUE_UNDEFINED:
50 [[fallthrough]];
51 case JSTaggedValue::VALUE_HOLE:
52 [[fallthrough]];
53 case JSTaggedValue::VALUE_NULL:
54 [[fallthrough]];
55 case JSTaggedValue::VALUE_FALSE: {
56 return false;
57 }
58 case JSTaggedValue::VALUE_TRUE: {
59 return true;
60 }
61 default: {
62 break;
63 }
64 }
65
66 if (IsBigInt()) {
67 BigInt *bigint = BigInt::Cast(GetTaggedObject());
68 return !bigint->IsZero();
69 }
70 if (IsHeapObject()) {
71 TaggedObject *obj = GetTaggedObject();
72 if (IsString()) {
73 auto str = static_cast<EcmaString *>(obj);
74 return EcmaStringAccessor(str).GetLength() != 0;
75 }
76 return true;
77 }
78 LOG_ECMA(FATAL) << "this branch is unreachable";
79 UNREACHABLE();
80 }
81
ToNumber(JSThread * thread,JSTaggedValue tagged)82 JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, JSTaggedValue tagged)
83 {
84 DISALLOW_GARBAGE_COLLECTION;
85 if (tagged.IsInt() || tagged.IsDouble()) {
86 return JSTaggedNumber(tagged);
87 }
88
89 switch (tagged.GetRawData()) {
90 case JSTaggedValue::VALUE_UNDEFINED:
91 case JSTaggedValue::VALUE_HOLE: {
92 return JSTaggedNumber(base::NAN_VALUE);
93 }
94 case JSTaggedValue::VALUE_TRUE: {
95 return JSTaggedNumber(1);
96 }
97 case JSTaggedValue::VALUE_FALSE:
98 case JSTaggedValue::VALUE_NULL: {
99 return JSTaggedNumber(0);
100 }
101 default: {
102 break;
103 }
104 }
105
106 if (tagged.IsString()) {
107 return StringToNumber(tagged);
108 }
109 if (tagged.IsECMAObject()) {
110 JSHandle<JSTaggedValue>taggedHandle(thread, tagged);
111 JSTaggedValue primValue = ToPrimitive(thread, taggedHandle, PREFER_NUMBER);
112 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
113 return ToNumber(thread, primValue);
114 }
115 if (tagged.IsSymbol()) {
116 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception());
117 }
118 if (tagged.IsBigInt()) {
119 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception());
120 }
121 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception());
122 }
123
ToNumber(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)124 JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
125 {
126 return ToNumber(thread, tagged.GetTaggedValue());
127 }
128
ToBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)129 JSTaggedValue JSTaggedValue::ToBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
130 {
131 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged));
132 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
133 switch (primValue->GetRawData()) {
134 case JSTaggedValue::VALUE_UNDEFINED:
135 case JSTaggedValue::VALUE_NULL: {
136 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a undefine or null value to a BigInt",
137 JSTaggedValue::Exception());
138 }
139 case JSTaggedValue::VALUE_TRUE: {
140 return BigInt::Int32ToBigInt(thread, 1).GetTaggedValue();
141 }
142 case JSTaggedValue::VALUE_FALSE: {
143 return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
144 }
145 default: {
146 break;
147 }
148 }
149
150 if (primValue->IsNumber()) {
151 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Number value to a BigInt", JSTaggedNumber::Exception());
152 }
153 if (primValue->IsString()) {
154 JSHandle<JSTaggedValue> value(thread, base::NumberHelper::StringToBigInt(thread, primValue));
155 if (value->IsBigInt()) {
156 return value.GetTaggedValue();
157 }
158 THROW_SYNTAX_ERROR_AND_RETURN(thread, "Cannot convert string to a BigInt,"
159 "because not allow Infinity, decimal points, or exponents",
160 JSTaggedValue::Exception());
161 }
162 if (primValue->IsSymbol()) {
163 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a BigInt", JSTaggedNumber::Exception());
164 }
165 if (primValue->IsBigInt()) {
166 return primValue.GetTaggedValue();
167 }
168 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a BigInt", JSTaggedNumber::Exception());
169 }
170
ToBigInt64(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)171 JSTaggedValue JSTaggedValue::ToBigInt64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
172 {
173 JSHandle<BigInt> value(thread, ToBigInt(thread, tagged));
174 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
175 JSHandle<BigInt> tVal = BigInt::GetUint64MaxBigInt(thread);
176 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
177 JSHandle<BigInt> int64bitVal = BigInt::FloorMod(thread, value, tVal);
178 JSHandle<BigInt> resValue = BigInt::GetInt64MaxBigInt(thread);
179 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
180 if (!BigInt::LessThan(int64bitVal.GetTaggedValue(), resValue.GetTaggedValue())) {
181 return BigInt::Subtract(thread, int64bitVal, tVal).GetTaggedValue();
182 } else {
183 return int64bitVal.GetTaggedValue();
184 }
185 }
186
ToBigUint64(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)187 JSTaggedValue JSTaggedValue::ToBigUint64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
188 {
189 JSHandle<BigInt> value(thread, ToBigInt(thread, tagged));
190 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
191 bool signFlag = value->GetSign();
192 uint32_t len = value->GetLength();
193 if (!signFlag && len <= 2) { // 2:2 int equal int64
194 return value.GetTaggedValue();
195 }
196 JSHandle<BigInt> tVal = BigInt::GetUint64MaxBigInt(thread);
197 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
198 return BigInt::FloorMod(thread, value, tVal).GetTaggedValue();
199 }
200
ToInteger(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)201 JSTaggedNumber JSTaggedValue::ToInteger(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
202 {
203 JSTaggedNumber number = ToNumber(thread, tagged);
204 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
205
206 return JSTaggedNumber(base::NumberHelper::TruncateDouble(number.GetNumber()));
207 }
208
ToInt32(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)209 int32_t JSTaggedValue::ToInt32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
210 {
211 JSTaggedNumber number = ToNumber(thread, tagged);
212 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
213 return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT32_BITS);
214 }
215
ToUint32(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)216 uint32_t JSTaggedValue::ToUint32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
217 {
218 return ToInt32(thread, tagged);
219 }
220
ToInt16(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)221 int16_t JSTaggedValue::ToInt16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
222 {
223 JSTaggedNumber number = ToNumber(thread, tagged);
224 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
225
226 return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT16_BITS);
227 }
228
ToUint16(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)229 uint16_t JSTaggedValue::ToUint16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
230 {
231 return ToInt16(thread, tagged);
232 }
233
ToInt8(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)234 int8_t JSTaggedValue::ToInt8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
235 {
236 JSTaggedNumber number = ToNumber(thread, tagged);
237 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
238
239 return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT8_BITS);
240 }
241
ToUint8(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)242 uint8_t JSTaggedValue::ToUint8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
243 {
244 return ToInt8(thread, tagged);
245 }
246
ToUint8Clamp(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)247 uint8_t JSTaggedValue::ToUint8Clamp(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
248 {
249 JSTaggedNumber number = ToNumber(thread, tagged);
250 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
251
252 double d = number.GetNumber();
253 if (std::isnan(d) || d <= 0) {
254 return 0;
255 }
256 if (d >= UINT8_MAX) {
257 return UINT8_MAX;
258 }
259
260 return lrint(d);
261 }
262
ToLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)263 JSTaggedNumber JSTaggedValue::ToLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
264 {
265 JSTaggedNumber len = ToInteger(thread, tagged);
266 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
267 if (len.GetNumber() < 0.0) {
268 return JSTaggedNumber(static_cast<double>(0));
269 }
270 if (len.GetNumber() > SAFE_NUMBER) {
271 return JSTaggedNumber(static_cast<double>(SAFE_NUMBER));
272 }
273 return len;
274 }
275
276 // ecma6 7.2 Testing and Comparison Operations
RequireObjectCoercible(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,const char * message)277 JSHandle<JSTaggedValue> JSTaggedValue::RequireObjectCoercible(JSThread *thread,
278 const JSHandle<JSTaggedValue> &tagged,
279 const char *message)
280 {
281 if (tagged->IsUndefinedOrNull()) {
282 THROW_TYPE_ERROR_AND_RETURN(thread, message, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
283 }
284 return tagged;
285 }
286
GetTypeString(JSThread * thread,PreferredPrimitiveType type)287 JSHandle<EcmaString> GetTypeString(JSThread *thread, PreferredPrimitiveType type)
288 {
289 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
290 if (type == NO_PREFERENCE) {
291 return JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString());
292 }
293 if (type == PREFER_NUMBER) {
294 return JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString());
295 }
296 return JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString());
297 }
298
IsInSharedHeap() const299 bool JSTaggedValue::IsInSharedHeap() const
300 {
301 if (IsHeapObject()) {
302 Region *region = Region::ObjectAddressToRange(value_);
303 return region->InSharedHeap();
304 }
305 return false;
306 }
307
ToPropertyKey(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)308 JSHandle<JSTaggedValue> JSTaggedValue::ToPropertyKey(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
309 {
310 if (tagged->IsStringOrSymbol() || tagged->IsNumber()) {
311 return tagged;
312 }
313 JSHandle<JSTaggedValue> key(thread, ToPrimitive(thread, tagged, PREFER_STRING));
314 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
315 if (key->IsSymbol()) {
316 return key;
317 }
318 JSHandle<EcmaString> string = ToString(thread, key);
319 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
320 return JSHandle<JSTaggedValue>::Cast(string);
321 }
322
IsInteger() const323 bool JSTaggedValue::IsInteger() const
324 {
325 if (!IsNumber()) {
326 return false;
327 }
328
329 if (IsInt()) {
330 return true;
331 }
332
333 double thisValue = GetDouble();
334 // If argument is NaN, +∞, or -∞, return false.
335 if (!std::isfinite(thisValue)) {
336 return false;
337 }
338
339 // If floor(abs(argument)) ≠ abs(argument), return false.
340 if (std::floor(std::abs(thisValue)) != std::abs(thisValue)) {
341 return false;
342 }
343
344 return true;
345 }
346
IsJSCOWArray() const347 bool JSTaggedValue::IsJSCOWArray() const
348 {
349 // Elements of JSArray are shared and properties are not yet.
350 return IsJSArray() && JSArray::Cast(GetTaggedObject())->GetElements().IsCOWArray();
351 }
352
IsStableJSArray(JSThread * thread) const353 bool JSTaggedValue::IsStableJSArray(JSThread *thread) const
354 {
355 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArray() &&
356 !thread->IsStableArrayElementsGuardiansInvalid();
357 }
358
IsStableJSArguments(JSThread * thread) const359 bool JSTaggedValue::IsStableJSArguments(JSThread *thread) const
360 {
361 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArguments() &&
362 !thread->IsStableArrayElementsGuardiansInvalid();
363 }
364
IsTaggedArray() const365 bool JSTaggedValue::IsTaggedArray() const
366 {
367 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTaggedArray();
368 }
369
IsJSProxy() const370 bool JSTaggedValue::IsJSProxy() const
371 {
372 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSProxy();
373 }
374
IsGeneratorObject() const375 bool JSTaggedValue::IsGeneratorObject() const
376 {
377 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorObject();
378 }
379
IsGeneratorContext() const380 bool JSTaggedValue::IsGeneratorContext() const
381 {
382 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorContext();
383 }
384
HasStableElements(JSThread * thread) const385 bool JSTaggedValue::HasStableElements(JSThread *thread) const
386 {
387 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableElements() &&
388 !thread->IsStableArrayElementsGuardiansInvalid();
389 }
390
WithinInt32() const391 bool JSTaggedValue::WithinInt32() const
392 {
393 if (!IsNumber()) {
394 return false;
395 }
396
397 double doubleValue = GetNumber();
398 if (base::bit_cast<int64_t>(doubleValue) == base::bit_cast<int64_t>(-0.0)) {
399 return false;
400 }
401
402 int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
403 return doubleValue == static_cast<double>(intvalue);
404 }
405
IsZero() const406 bool JSTaggedValue::IsZero() const
407 {
408 if (GetRawData() == VALUE_ZERO) {
409 return true;
410 }
411 if (IsDouble()) {
412 const double limit = 1e-8;
413 return (std::abs(GetDouble() - 0.0) <= limit);
414 }
415 return false;
416 }
417
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)418 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
419 {
420 if (x->IsNumber()) {
421 return EqualNumber(thread, x, y);
422 }
423
424 if (x->IsString()) {
425 return EqualString(thread, x, y);
426 }
427
428 if (x->IsBoolean()) {
429 JSTaggedNumber xNumber = ToNumber(thread, x);
430 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
431 return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
432 }
433
434 if (x->IsSymbol()) {
435 return EqualSymbol(thread, x, y);
436 }
437
438 if (x->IsBigInt()) {
439 return EqualBigInt(thread, x, y);
440 }
441
442 if (x->IsHeapObject()) {
443 return EqualHeapObject(thread, x, y);
444 }
445
446 return EqualNullOrUndefined(x, y);
447 }
448
EqualNumber(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)449 bool JSTaggedValue::EqualNumber(JSThread *thread, const JSHandle<JSTaggedValue> &x,
450 const JSHandle<JSTaggedValue> &y)
451 {
452 if (y->IsNumber()) {
453 return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
454 }
455 if (y->IsString()) {
456 JSTaggedNumber yNumber = ToNumber(thread, y);
457 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
458 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
459 }
460 if (y->IsBoolean()) {
461 JSTaggedNumber yNumber = ToNumber(thread, y);
462 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
463 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
464 }
465 if (y->IsBigInt()) {
466 return Equal(thread, y, x);
467 }
468 if (y->IsHeapObject() && !y->IsSymbol()) {
469 if (!(y->IsECMAObject())) {
470 return false;
471 }
472 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
473 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
474 return Equal(thread, x, yPrimitive);
475 }
476 return false;
477 }
478
EqualString(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)479 bool JSTaggedValue::EqualString(JSThread *thread, const JSHandle<JSTaggedValue> &x,
480 const JSHandle<JSTaggedValue> &y)
481 {
482 if (y->IsString()) {
483 return EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(),
484 JSHandle<EcmaString>(x),
485 JSHandle<EcmaString>(y));
486 }
487 if (y->IsNumber()) {
488 JSTaggedNumber xNumber = ToNumber(thread, x);
489 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
490 return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
491 }
492 if (y->IsBoolean()) {
493 JSTaggedNumber xNumber = ToNumber(thread, x);
494 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
495 JSTaggedNumber yNumber = ToNumber(thread, y);
496 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
497 return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
498 }
499 if (y->IsBigInt()) {
500 return Equal(thread, y, x);
501 }
502 if (y->IsHeapObject() && !y->IsSymbol()) {
503 if (!(y->IsECMAObject())) {
504 return false;
505 }
506 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
507 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
508 return Equal(thread, x, yPrimitive);
509 }
510 return false;
511 }
512
EqualSymbol(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)513 bool JSTaggedValue::EqualSymbol(JSThread *thread, const JSHandle<JSTaggedValue> &x,
514 const JSHandle<JSTaggedValue> &y)
515 {
516 if (y->IsSymbol()) {
517 return x.GetTaggedValue() == y.GetTaggedValue();
518 }
519 if (y->IsBigInt() || y->IsString()) {
520 return false;
521 }
522 if (y->IsHeapObject()) {
523 if (!(y->IsECMAObject())) {
524 return false;
525 }
526 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
527 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
528 return Equal(thread, x, yPrimitive);
529 }
530 return false;
531 }
532
EqualBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)533 bool JSTaggedValue::EqualBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &x,
534 const JSHandle<JSTaggedValue> &y)
535 {
536 if (y->IsBigInt()) {
537 return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
538 }
539 if (y->IsString()) {
540 JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
541 if (!yNumber->IsBigInt()) {
542 return false;
543 }
544 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
545 }
546 if (y->IsBoolean()) {
547 JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
548 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
549 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
550 }
551 if (y->IsNumber()) {
552 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
553 return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
554 }
555 if (y->IsHeapObject() && !y->IsSymbol()) {
556 if (!(y->IsECMAObject())) {
557 return false;
558 }
559 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
560 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
561 return Equal(thread, x, yPrimitive);
562 }
563 return false;
564 }
565
EqualHeapObject(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)566 bool JSTaggedValue::EqualHeapObject(JSThread *thread, const JSHandle<JSTaggedValue> &x,
567 const JSHandle<JSTaggedValue> &y)
568 {
569 if (y->IsHeapObject()) {
570 // if same type, must call Type::StrictEqual()
571 JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
572 JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
573 if (xType == yType) {
574 return StrictEqual(thread, x, y);
575 }
576 }
577 if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
578 if (!(x->IsECMAObject())) {
579 return false;
580 }
581 JSHandle<JSTaggedValue> xPrimitive(thread, ToPrimitive(thread, x));
582 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
583 return Equal(thread, xPrimitive, y);
584 }
585 return false;
586 }
587
EqualNullOrUndefined(const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)588 bool JSTaggedValue::EqualNullOrUndefined(const JSHandle<JSTaggedValue> &x,
589 const JSHandle<JSTaggedValue> &y)
590 {
591 if (x->IsNull() && y->IsNull()) {
592 return true;
593 }
594 if (x->IsUndefined() && y->IsUndefined()) {
595 return true;
596 }
597 if (x->IsNull() && y->IsUndefined()) {
598 return true;
599 }
600 if (x->IsUndefined() && y->IsNull()) {
601 return true;
602 }
603 return false;
604 }
605
606 static const uint32_t POWERS_OF_10[] = {
607 1,
608 10,
609 100,
610 1000,
611 10 * 1000,
612 100 * 1000,
613 1000 * 1000,
614 10 * 1000 * 1000,
615 100 * 1000 * 1000,
616 1000 * 1000 * 1000,
617 };
618
IntLexicographicCompare(JSTaggedValue x,JSTaggedValue y)619 int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
620 {
621 ASSERT(x.IsInt() && y.IsInt());
622 int xValue = x.GetInt();
623 int yValue = y.GetInt();
624 if (xValue == yValue) {
625 return 0;
626 }
627 if (xValue == 0 || yValue == 0) {
628 return xValue > yValue ? 1 : -1;
629 }
630 uint32_t unsignedX = static_cast<uint32_t>(xValue);
631 uint32_t unsignedY = static_cast<uint32_t>(yValue);
632 if (yValue > 0) {
633 if (xValue < 0) {
634 return -1;
635 }
636 } else {
637 if (xValue > 0) {
638 return 1;
639 }
640 unsignedX = static_cast<uint32_t>(base::NegateWithWraparound(xValue));
641 unsignedY = static_cast<uint32_t>(base::NegateWithWraparound(yValue));
642 }
643 int xLog2 = 31 - __builtin_clz(unsignedX);
644 int xDigit = ((xLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
645 xDigit -= unsignedX < POWERS_OF_10[xDigit];
646
647 int yLog2 = 31 - __builtin_clz(unsignedY);
648 int yDigit = ((yLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
649 yDigit -= unsignedY < POWERS_OF_10[yDigit];
650
651 int res = 0;
652 if (xDigit > yDigit) {
653 // X has fewer digits. We would like to simply scale up X but that
654 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
655 // be scaled up to 9_000_000_000. So we scale up by the next
656 // smallest power and scale down Y to drop one digit. It is OK to
657 // drop one digit from the longer integer since the final digit is
658 // past the length of the shorter integer.
659 unsignedY *= POWERS_OF_10[xDigit - yDigit - 1];
660 unsignedX /= 10; // 10 : Decimal
661 res = 1;
662 }
663 if (yDigit > xDigit) {
664 unsignedX *= POWERS_OF_10[yDigit - xDigit - 1];
665 unsignedY /= 10; // 10 : Decimal
666 res = -1;
667 }
668 if (unsignedX > unsignedY) {
669 return 1;
670 }
671
672 if (unsignedY > unsignedX) {
673 return -1;
674 }
675 return res;
676 }
677
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)678 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
679 const JSHandle<JSTaggedValue> &y)
680 {
681 if (x->IsDate() && y->IsDate()) {
682 double timeX = JSDate::Cast(x->GetTaggedObject())->GetTimeValue().GetDouble();
683 double timeY = JSDate::Cast(y->GetTaggedObject())->GetTimeValue().GetDouble();
684 return StrictNumberCompare(timeX, timeY);
685 }
686 JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
687 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
688 JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
689 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
690 if (primX->IsString() && primY->IsString()) {
691 auto xHandle = JSHandle<EcmaString>(primX);
692 auto yHandle = JSHandle<EcmaString>(primY);
693 int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
694 if (result < 0) {
695 return ComparisonResult::LESS;
696 }
697 if (result == 0) {
698 return ComparisonResult::EQUAL;
699 }
700 return ComparisonResult::GREAT;
701 }
702 if (primX->IsBigInt()) {
703 if (primY->IsNumber()) {
704 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
705 return BigInt::CompareWithNumber(bigint, primY);
706 } else if (primY->IsString()) {
707 JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
708 if (!bigY->IsBigInt()) {
709 return ComparisonResult::UNDEFINED;
710 }
711 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
712 } else {
713 JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
714 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
715 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
716 }
717 }
718 if (primY->IsBigInt()) {
719 ComparisonResult res = Compare(thread, primY, primX);
720 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
721 if (res == ComparisonResult::GREAT) {
722 return ComparisonResult::LESS;
723 } else if (res == ComparisonResult::LESS) {
724 return ComparisonResult::GREAT;
725 }
726 return res;
727 }
728 double resultX = 0;
729 double resultY = 0;
730 if (primX->IsNumber()) {
731 resultX = primX->GetNumber();
732 } else {
733 JSTaggedNumber xNumber = ToNumber(thread, x);
734 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
735 resultX = xNumber.GetNumber();
736 }
737 if (primY->IsNumber()) {
738 resultY = primY->GetNumber();
739 } else {
740 JSTaggedNumber yNumber = ToNumber(thread, y);
741 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
742 resultY = yNumber.GetNumber();
743 }
744 return StrictNumberCompare(resultX, resultY);
745 }
746
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)747 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
748 {
749 if (x.IsNumber() && y.IsNumber()) {
750 return true;
751 }
752 if (x.IsBoolean() && y.IsBoolean()) {
753 return true;
754 }
755 if (x.IsString() && y.IsString()) {
756 return true;
757 }
758 if (x.IsHeapObject() && y.IsHeapObject()) {
759 return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
760 }
761
762 return false;
763 }
764
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)765 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
766 PreferredPrimitiveType type)
767 {
768 if (tagged->IsECMAObject()) {
769 EcmaVM *vm = thread->GetEcmaVM();
770 JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
771
772 JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
773 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
774 if (!exoticToprim->IsUndefined()) {
775 JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
776 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
777 EcmaRuntimeCallInfo *info =
778 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
779 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
780 info->SetCallArg(value);
781 JSTaggedValue valueResult = JSFunction::Call(info);
782 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
783 if (!valueResult.IsECMAObject()) {
784 return valueResult;
785 }
786 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert object to primitive value",
787 JSTaggedValue::Exception());
788 } else {
789 type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
790 return OrdinaryToPrimitive(thread, tagged, type);
791 }
792 }
793 return tagged.GetTaggedValue();
794 }
795
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)796 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
797 PreferredPrimitiveType type)
798 {
799 static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
800 ASSERT(tagged->IsECMAObject());
801 auto globalConst = thread->GlobalConstants();
802 for (uint8_t i = 0; i < 2; i++) { // 2: 2 means value has 2 target types, string or value.
803 JSHandle<JSTaggedValue> keyString;
804 if ((static_cast<uint8_t>(type) ^ i) != 0) {
805 keyString = globalConst->GetHandledToStringString();
806 } else {
807 keyString = globalConst->GetHandledValueOfString();
808 }
809 JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
810 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
811 if (entryfunc->IsCallable()) {
812 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
813 EcmaRuntimeCallInfo *info =
814 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
815 JSTaggedValue valueResult = JSFunction::Call(info);
816 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
817 if (!valueResult.IsECMAObject()) {
818 return valueResult;
819 }
820 }
821 }
822 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
823 }
824
ToString(JSThread * thread,JSTaggedValue val)825 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
826 {
827 JSHandle<JSTaggedValue> tagged(thread, val);
828 return ToString(thread, tagged);
829 }
830
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)831 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
832 {
833 if (tagged->IsString()) {
834 return JSHandle<EcmaString>(tagged);
835 }
836 auto globalConst = thread->GlobalConstants();
837 if (tagged->IsSpecial()) {
838 switch (tagged->GetRawData()) {
839 case VALUE_UNDEFINED: {
840 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
841 }
842 case VALUE_NULL: {
843 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
844 }
845 case VALUE_TRUE: {
846 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
847 }
848 case VALUE_FALSE: {
849 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
850 }
851 case VALUE_HOLE: {
852 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
853 }
854 default:
855 break;
856 }
857 }
858
859 if (tagged->IsNumber()) {
860 return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
861 }
862
863 if (tagged->IsBigInt()) {
864 JSHandle<BigInt> taggedValue(tagged);
865 return BigInt::ToString(thread, taggedValue);
866 }
867
868 if (tagged->IsNativePointer()) {
869 return NativePointerToString(thread, tagged);
870 }
871
872 auto emptyStr = globalConst->GetHandledEmptyString();
873 if (tagged->IsECMAObject()) {
874 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
875 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
876 return ToString(thread, primValue);
877 }
878 // Already Include Symbol
879 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
880 }
881
NativePointerToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)882 JSHandle<EcmaString> JSTaggedValue::NativePointerToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
883 {
884 JSHandle<JSNativePointer> taggedHandle(tagged);
885 std::stringstream stringstream;
886 stringstream << std::hex << taggedHandle->GetExternalPointer();
887 std::string nativePtrStr = "[External: " + stringstream.str() + "]";
888
889 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
890 return factory->NewFromASCII(nativePtrStr);
891 }
892
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)893 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
894 {
895 if (tagged->IsNumber()) {
896 return tagged.GetTaggedValue();
897 }
898
899 if (tagged->IsString()) {
900 JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
901 if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), JSHandle<EcmaString>(tagged), str)) {
902 return JSTaggedValue(-0.0);
903 }
904 JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
905 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
906 if (SameValue(ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
907 return tmp.GetTaggedValue();
908 }
909 }
910 return JSTaggedValue::Undefined();
911 }
912
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)913 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
914 {
915 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
916 if (tagged->IsInt() || tagged->IsDouble()) {
917 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
918 }
919
920 switch (tagged->GetRawData()) {
921 case JSTaggedValue::VALUE_UNDEFINED: {
922 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
923 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
924 }
925 case JSTaggedValue::VALUE_HOLE: {
926 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
927 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
928 }
929 case JSTaggedValue::VALUE_NULL: {
930 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
931 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
932 }
933 case JSTaggedValue::VALUE_TRUE:
934 case JSTaggedValue::VALUE_FALSE: {
935 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
936 }
937 default: {
938 break;
939 }
940 }
941
942 if (tagged->IsECMAObject()) {
943 return JSHandle<JSObject>::Cast(tagged);
944 }
945 if (tagged->IsSymbol()) {
946 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
947 }
948 if (tagged->IsString()) {
949 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
950 }
951 if (tagged->IsBigInt()) {
952 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
953 }
954 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
955 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
956 }
957
958 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)959 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
960 const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
961 {
962 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
963 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
964 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
965 std::string message = "Cannot read property ";
966 message.append(keyStr).append(" of ").append(objStr);
967 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
968 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
969 }
970 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
971
972 if (obj->IsJSProxy()) {
973 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
974 }
975 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
976 return JSTypedArray::GetProperty(thread, obj, key);
977 }
978 if (obj->IsModuleNamespace()) {
979 return ModuleNamespace::GetProperty(thread, obj, key);
980 }
981
982 if (obj->IsSpecialContainer()) {
983 return GetJSAPIProperty(thread, obj, key);
984 }
985
986 return JSObject::GetProperty(thread, obj, key, sCheckMode);
987 }
988
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)989 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
990 {
991 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
992 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
993 std::string message = "Cannot read property ";
994 message.append(ToCString(key)).append(" of ").append(objStr);
995 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
996 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
997 }
998
999 if (obj->IsJSProxy()) {
1000 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1001 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1002 }
1003
1004 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1005 return JSTypedArray::GetProperty(thread, obj, key);
1006 }
1007
1008 if (obj->IsSpecialContainer()) {
1009 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1010 return GetJSAPIProperty(thread, obj, keyHandle);
1011 }
1012
1013 return JSObject::GetProperty(thread, obj, key);
1014 }
1015
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)1016 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1017 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
1018 {
1019 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1020 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
1021 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
1022 std::string message = "Cannot read property ";
1023 message.append(keyStr).append(" of ").append(objStr);
1024 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
1025 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
1026 }
1027 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1028
1029 if (obj->IsJSProxy()) {
1030 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
1031 }
1032 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1033 return JSTypedArray::GetProperty(thread, obj, key, receiver);
1034 }
1035
1036 if (obj->IsSpecialContainer()) {
1037 return GetJSAPIProperty(thread, obj, key);
1038 }
1039
1040 return JSObject::GetProperty(thread, obj, key, receiver);
1041 }
1042
1043 // 7.3.3 Set (O, P, V, Throw)
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow,SCheckMode checkMode)1044 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1045 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow,
1046 SCheckMode checkMode)
1047 {
1048 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1049 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1050 }
1051
1052 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1053
1054 // 4. Let success be O.[[Set]](P, V, O).
1055 bool success = false;
1056 if (obj->IsJSProxy()) {
1057 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
1058 } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1059 success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
1060 } else if (obj->IsModuleNamespace()) {
1061 success = ModuleNamespace::SetProperty(thread, mayThrow);
1062 } else if (obj->IsSpecialContainer()) {
1063 success = SetJSAPIProperty(thread, obj, key, value);
1064 } else {
1065 success = JSObject::SetProperty(thread, obj, key, value, mayThrow, checkMode);
1066 }
1067 // 5. ReturnIfAbrupt(success).
1068 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1069 // 6. If success is false and Throw is true, throw a TypeError exception.
1070 // have done in JSObject::SetPropert.
1071 return success;
1072 }
1073
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)1074 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
1075 const JSHandle<JSTaggedValue> &value, bool mayThrow)
1076 {
1077 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1078 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1079 }
1080
1081 // 4. Let success be O.[[Set]](P, V, O).
1082 bool success = false;
1083 if (obj->IsJSProxy()) {
1084 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1085 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
1086 } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1087 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1088 success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
1089 } else if (obj->IsModuleNamespace()) {
1090 success = ModuleNamespace::SetProperty(thread, mayThrow);
1091 } else if (obj->IsSpecialContainer()) {
1092 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1093 success = SetJSAPIProperty(thread, obj, keyHandle, value);
1094 } else {
1095 success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
1096 }
1097 // 5. ReturnIfAbrupt(success).
1098 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1099 // 6. If success is false and Throw is true, throw a TypeError exception.
1100 // have done in JSObject::SetPropert.
1101 return success;
1102 }
1103
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)1104 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1105 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
1106 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
1107 {
1108 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1109 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1110 }
1111
1112 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1113
1114 // 4. Let success be O.[[Set]](P, V, O).
1115 bool success = false;
1116 if (obj->IsJSProxy()) {
1117 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
1118 } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1119 success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
1120 } else if (obj->IsModuleNamespace()) {
1121 success = ModuleNamespace::SetProperty(thread, mayThrow);
1122 } else if (obj->IsSpecialContainer()) {
1123 success = SetJSAPIProperty(thread, obj, key, value);
1124 } else {
1125 success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
1126 }
1127 // 5. ReturnIfAbrupt(success).
1128 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1129 // 6. If success is false and Throw is true, throw a TypeError exception.
1130 // have done in JSObject::SetPropert.
1131 return success;
1132 }
1133
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1134 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1135 const JSHandle<JSTaggedValue> &key)
1136 {
1137 if (obj->IsJSProxy()) {
1138 return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
1139 }
1140
1141 if (obj->IsModuleNamespace()) {
1142 return ModuleNamespace::DeleteProperty(thread, obj, key);
1143 }
1144
1145 if (obj->IsTypedArray()) {
1146 return JSTypedArray::DeleteProperty(thread, obj, key);
1147 }
1148
1149 if (obj->IsSpecialContainer()) {
1150 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
1151 }
1152
1153 return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
1154 }
1155
1156 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1157 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1158 const JSHandle<JSTaggedValue> &key)
1159 {
1160 if (!obj->IsECMAObject()) {
1161 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
1162 }
1163 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1164
1165 // 3. Let success be O.[[Delete]](P).
1166 bool success = DeleteProperty(thread, obj, key);
1167
1168 // 4. ReturnIfAbrupt(success).
1169 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1170 // 5. If success is false, throw a TypeError exception
1171 if (!success) {
1172 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
1173 }
1174 return success;
1175 }
1176
1177 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1178 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1179 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
1180 {
1181 // 1. Assert: Type(O) is Object.
1182 // 2. Assert: IsPropertyKey(P) is true.
1183 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1184 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1185 // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
1186 bool success = DefineOwnProperty(thread, obj, key, desc);
1187 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1188 // 4. If success is false, throw a TypeError exception.
1189 if (!success) {
1190 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot define property", false);
1191 }
1192 return success;
1193 }
1194
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc,SCheckMode sCheckMode)1195 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1196 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
1197 SCheckMode sCheckMode)
1198 {
1199 if (obj->IsJSArray()) {
1200 return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1201 }
1202
1203 if (obj->IsJSSharedArray()) {
1204 return JSSharedArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc, sCheckMode);
1205 }
1206
1207 if (obj->IsJSProxy()) {
1208 return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1209 }
1210
1211 if (obj->IsTypedArray()) {
1212 return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
1213 }
1214
1215 if (obj->IsModuleNamespace()) {
1216 return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
1217 }
1218
1219 if (obj->IsSpecialContainer()) {
1220 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
1221 }
1222
1223 return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1224 }
1225
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1226 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1227 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1228 {
1229 if (obj->IsJSProxy()) {
1230 return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1231 }
1232 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1233 return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
1234 }
1235 if (obj->IsModuleNamespace()) {
1236 return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
1237 }
1238 if (obj->IsSpecialContainer()) {
1239 return GetContainerProperty(thread, obj, key, desc);
1240 }
1241 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1242 }
1243
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto,bool isChangeProto)1244 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1245 const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
1246 {
1247 if (obj->IsJSShared() || proto->IsJSShared()) {
1248 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetProtoWithSendable), false);
1249 }
1250
1251 if (obj->IsJSProxy()) {
1252 return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
1253 }
1254 if (obj->IsModuleNamespace()) {
1255 return ModuleNamespace::SetPrototype(obj, proto);
1256 }
1257 if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
1258 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
1259 }
1260 if (obj->IsJSFunction() && proto->IsJSFunction()) {
1261 JSHandle<JSFunction> objFunc = JSHandle<JSFunction>::Cast(obj);
1262 JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass());
1263 if (objProtoOrHClass.IsJSHClass() && objFunc->IsDerivedConstructor()) {
1264 JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
1265 objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype());
1266 }
1267 }
1268
1269 return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto, isChangeProto);
1270 }
1271
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1272 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1273 {
1274 if (!obj->IsECMAObject()) {
1275 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
1276 }
1277 if (obj->IsJSProxy()) {
1278 return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
1279 }
1280 return JSObject::GetPrototype(JSHandle<JSObject>(obj));
1281 }
1282
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1283 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1284 {
1285 if (obj->IsJSProxy()) {
1286 return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
1287 }
1288 if (obj->IsModuleNamespace()) {
1289 return ModuleNamespace::PreventExtensions();
1290 }
1291 return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
1292 }
1293
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1294 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1295 {
1296 if (obj->IsJSProxy()) {
1297 return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
1298 }
1299 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1300 return JSTypedArray::OwnPropertyKeys(thread, obj);
1301 }
1302 if (obj->IsSpecialContainer()) {
1303 return GetOwnContainerPropertyKeys(thread, obj);
1304 }
1305 if (obj->IsModuleNamespace()) {
1306 return ModuleNamespace::OwnPropertyKeys(thread, obj);
1307 }
1308 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1309 }
1310
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)1311 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
1312 const JSHandle<JSTaggedValue> &obj, uint32_t filter)
1313 {
1314 if (obj->IsJSProxy()) {
1315 return JSProxy::GetAllPropertyKeys(thread, JSHandle<JSProxy>(obj), filter);
1316 }
1317 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1318 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
1319 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1320 }
1321 if (obj->IsSpecialContainer()) {
1322 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
1323 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1324 }
1325 if (obj->IsModuleNamespace()) {
1326 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
1327 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1328 }
1329 return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
1330 }
1331
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1332 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1333 {
1334 ASSERT(!obj->IsJSProxy());
1335 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1336 return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
1337 }
1338 if (obj->IsSpecialContainer()) {
1339 return GetOwnContainerEnumPropertyKeys(thread, obj);
1340 }
1341 if (obj->IsModuleNamespace()) {
1342 return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
1343 }
1344 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1345 }
1346
1347 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1348 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1349 const JSHandle<JSTaggedValue> &key)
1350 {
1351 if (obj->IsJSProxy()) {
1352 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
1353 }
1354 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1355 return JSTypedArray::HasProperty(thread, obj, key);
1356 }
1357 if (obj->IsModuleNamespace()) {
1358 return ModuleNamespace::HasProperty(thread, obj, key);
1359 }
1360 if (obj->IsSpecialContainer()) {
1361 return HasContainerProperty(thread, obj, key);
1362 }
1363 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1364 }
1365
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)1366 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
1367 {
1368 if (obj->IsJSProxy()) {
1369 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1370 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1371 }
1372 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1373 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1374 return JSTypedArray::HasProperty(thread, obj, keyHandle);
1375 }
1376 if (obj->IsSpecialContainer()) {
1377 return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
1378 }
1379 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1380 }
1381
1382 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1383 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1384 const JSHandle<JSTaggedValue> &key)
1385 {
1386 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1387
1388 PropertyDescriptor desc(thread);
1389 return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
1390 }
1391
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)1392 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1393 {
1394 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1395
1396 PropertyDescriptor desc(thread);
1397 return JSObject::GlobalGetOwnProperty(thread, key, desc);
1398 }
1399
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1400 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1401 {
1402 // 1. If v is an Object, return true.
1403 if (tagged->IsECMAObject()) {
1404 return true;
1405 }
1406 // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
1407 if (tagged->IsSymbol()) {
1408 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1409 auto *table = env->GetRegisterSymbols().GetObject<SymbolTable>();
1410 JSTaggedValue key = table->FindSymbol(tagged.GetTaggedValue());
1411 if (key.IsUndefined()) {
1412 return true;
1413 }
1414 }
1415 // 3. Return false.
1416 return false;
1417 }
1418
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1419 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1420 {
1421 if (tagged->IsInt() && tagged->GetInt() >= 0) {
1422 return JSTaggedNumber(tagged.GetTaggedValue());
1423 }
1424 if (tagged->IsUndefined()) {
1425 return JSTaggedNumber(0);
1426 }
1427 JSTaggedNumber integerIndex = ToNumber(thread, tagged);
1428 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
1429 if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
1430 return integerIndex;
1431 }
1432 double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
1433 if (len < 0.0 || len > SAFE_NUMBER) {
1434 THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
1435 JSTaggedNumber::Exception());
1436 }
1437 return JSTaggedNumber(len);
1438 }
1439
1440 // 9.4.2.4 ArraySetLength 3 to 7
ToArrayLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,uint32_t * output)1441 bool JSTaggedValue::ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output)
1442 {
1443 // 3. Let newLen be ToUint32(Desc.[[Value]]).
1444 uint32_t newLen = ToUint32(thread, tagged);
1445 // 4. ReturnIfAbrupt(newLen).
1446 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1447
1448 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
1449 JSTaggedNumber numberLen = ToNumber(thread, tagged);
1450 // 6. ReturnIfAbrupt(newLen).
1451 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1452
1453 // 7. If newLen != numberLen, throw a RangeError exception.
1454 if (JSTaggedNumber(newLen) != numberLen) {
1455 THROW_RANGE_ERROR_AND_RETURN(thread, "Not a valid array length", false);
1456 }
1457
1458 *output = newLen;
1459 return true;
1460 }
1461
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1462 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1463 {
1464 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1465
1466 if (obj->IsNumber()) {
1467 return JSHandle<JSTaggedValue>(thread,
1468 env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1469 }
1470 if (obj->IsBoolean()) {
1471 return JSHandle<JSTaggedValue>(thread,
1472 env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1473 }
1474 if (obj->IsString()) {
1475 return JSHandle<JSTaggedValue>(thread,
1476 env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1477 }
1478 if (obj->IsSymbol()) {
1479 return JSHandle<JSTaggedValue>(thread,
1480 env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1481 }
1482 if (obj->IsBigInt()) {
1483 return JSHandle<JSTaggedValue>(thread,
1484 env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1485 }
1486 return obj;
1487 }
1488
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1489 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1490 {
1491 if (obj->IsUndefined()) {
1492 return JSTaggedValue::Undefined();
1493 }
1494
1495 ASSERT(obj->IsECMAObject());
1496 return JSTaggedValue::GetPrototype(thread, obj);
1497 }
1498
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1499 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1500 const JSHandle<JSTaggedValue> &key)
1501 {
1502 auto *hclass = obj->GetTaggedObject()->GetClass();
1503 JSType jsType = hclass->GetObjectType();
1504 switch (jsType) {
1505 case JSType::JS_API_ARRAY_LIST: {
1506 return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
1507 }
1508 case JSType::JS_API_QUEUE: {
1509 return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
1510 }
1511 case JSType::JS_API_PLAIN_ARRAY: {
1512 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1513 }
1514 case JSType::JS_API_DEQUE: {
1515 return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
1516 }
1517 case JSType::JS_API_STACK: {
1518 return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
1519 }
1520 case JSType::JS_API_LIST: {
1521 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1522 return list->Has(key.GetTaggedValue());
1523 }
1524 case JSType::JS_API_LINKED_LIST: {
1525 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1526 return linkedList->Has(key.GetTaggedValue());
1527 }
1528 case JSType::JS_API_HASH_MAP:
1529 case JSType::JS_API_HASH_SET:
1530 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1531 case JSType::JS_API_LIGHT_WEIGHT_SET:
1532 case JSType::JS_API_TREE_MAP:
1533 case JSType::JS_API_TREE_SET: {
1534 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1535 }
1536 case JSType::JS_API_VECTOR: {
1537 return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
1538 }
1539 case JSType::JS_API_BITVECTOR: {
1540 return JSHandle<JSAPIBitVector>::Cast(obj)->Has(key.GetTaggedValue());
1541 }
1542 default: {
1543 LOG_ECMA(FATAL) << "this branch is unreachable";
1544 UNREACHABLE();
1545 }
1546 }
1547 return false;
1548 }
1549
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1550 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1551 {
1552 auto *hclass = obj->GetTaggedObject()->GetClass();
1553 JSType jsType = hclass->GetObjectType();
1554 switch (jsType) {
1555 case JSType::JS_API_ARRAY_LIST: {
1556 return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1557 }
1558 case JSType::JS_API_QUEUE: {
1559 return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1560 }
1561 case JSType::JS_API_PLAIN_ARRAY: {
1562 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1563 }
1564 case JSType::JS_API_DEQUE: {
1565 return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1566 }
1567 case JSType::JS_API_STACK: {
1568 return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1569 }
1570 case JSType::JS_API_LIST: {
1571 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1572 }
1573 case JSType::JS_API_LINKED_LIST: {
1574 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1575 }
1576 case JSType::JS_API_HASH_MAP:
1577 case JSType::JS_API_HASH_SET:
1578 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1579 case JSType::JS_API_LIGHT_WEIGHT_SET:
1580 case JSType::JS_API_TREE_MAP:
1581 case JSType::JS_API_TREE_SET: {
1582 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1583 }
1584 case JSType::JS_API_VECTOR: {
1585 return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1586 }
1587 case JSType::JS_API_BITVECTOR: {
1588 return JSAPIBitVector::OwnKeys(thread, JSHandle<JSAPIBitVector>::Cast(obj));
1589 }
1590 default: {
1591 LOG_ECMA(FATAL) << "this branch is unreachable";
1592 UNREACHABLE();
1593 }
1594 }
1595 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1596 }
1597
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1598 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1599 const JSHandle<JSTaggedValue> &obj)
1600 {
1601 auto *hclass = obj->GetTaggedObject()->GetClass();
1602 JSType jsType = hclass->GetObjectType();
1603 switch (jsType) {
1604 case JSType::JS_API_QUEUE: {
1605 return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1606 }
1607 case JSType::JS_API_DEQUE: {
1608 return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1609 }
1610 case JSType::JS_API_LIST: {
1611 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1612 }
1613 case JSType::JS_API_LINKED_LIST: {
1614 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1615 }
1616 case JSType::JS_API_VECTOR:
1617 case JSType::JS_API_BITVECTOR:
1618 case JSType::JS_API_STACK:
1619 case JSType::JS_API_ARRAY_LIST:
1620 case JSType::JS_API_PLAIN_ARRAY:
1621 case JSType::JS_API_HASH_MAP:
1622 case JSType::JS_API_HASH_SET:
1623 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1624 case JSType::JS_API_LIGHT_WEIGHT_SET:
1625 case JSType::JS_API_TREE_MAP:
1626 case JSType::JS_API_TREE_SET: {
1627 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1628 }
1629 default: {
1630 UNREACHABLE();
1631 }
1632 }
1633 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1634 }
1635
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1636 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1637 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1638 {
1639 if (key->IsInteger()) {
1640 auto *hclass = obj->GetTaggedObject()->GetClass();
1641 JSType jsType = hclass->GetObjectType();
1642 switch (jsType) {
1643 case JSType::JS_API_ARRAY_LIST: {
1644 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1645 }
1646 case JSType::JS_API_QUEUE: {
1647 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1648 }
1649 case JSType::JS_API_DEQUE: {
1650 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1651 }
1652 case JSType::JS_API_STACK: {
1653 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1654 }
1655 case JSType::JS_API_LIST: {
1656 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1657 }
1658 case JSType::JS_API_LINKED_LIST: {
1659 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1660 }
1661 case JSType::JS_API_PLAIN_ARRAY: {
1662 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1663 }
1664 case JSType::JS_API_VECTOR: {
1665 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1666 }
1667 case JSType::JS_API_BITVECTOR: {
1668 return JSAPIBitVector::GetOwnProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1669 }
1670 default: {
1671 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1672 }
1673 }
1674 } else {
1675 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1676 }
1677 return false;
1678 }
1679
StringToNumber(JSTaggedValue tagged)1680 JSTaggedNumber JSTaggedValue::StringToNumber(JSTaggedValue tagged)
1681 {
1682 EcmaStringAccessor strAccessor(tagged);
1683 size_t strLen = strAccessor.GetLength();
1684 if (strLen == 0) {
1685 return JSTaggedNumber(0);
1686 }
1687 if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) {
1688 uint32_t index;
1689 // fast path: get integer from string's hash value
1690 if (strAccessor.TryToGetInteger(&index)) {
1691 return JSTaggedNumber(index);
1692 }
1693 Span<const uint8_t> str = strAccessor.FastToUtf8Span();
1694 if (strAccessor.GetLength() == 0) {
1695 return JSTaggedNumber(0);
1696 }
1697 auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), tagged);
1698 if (isSuccess) {
1699 return result;
1700 }
1701 }
1702 CVector<uint8_t> buf;
1703 Span<const uint8_t> str = strAccessor.ToUtf8Span(buf);
1704 double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
1705 base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
1706 return JSTaggedNumber(d);
1707 }
1708
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1709 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1710 {
1711 // 1. Let primValue be ? ToPrimitive(value, number)
1712 JSTaggedValue primValue = ToPrimitive(thread, tagged, PREFER_NUMBER);
1713 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1714 // 2. If Type(primValue) is BigInt, return primValue.
1715 if (primValue.IsBigInt()) {
1716 return JSHandle<JSTaggedValue>(thread, primValue);
1717 }
1718 // 3. Return ? ToNumber(primValue).
1719 JSTaggedNumber number = ToNumber(thread, primValue);
1720 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1721 JSHandle<JSTaggedValue> value(thread, number);
1722 return value;
1723 }
1724
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1725 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1726 const JSHandle<JSTaggedValue> &key)
1727 {
1728 if (key->IsInteger()) {
1729 auto *hclass = obj->GetTaggedObject()->GetClass();
1730 JSType jsType = hclass->GetObjectType();
1731 switch (jsType) {
1732 case JSType::JS_API_ARRAY_LIST: {
1733 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1734 }
1735 case JSType::JS_API_LIST: {
1736 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1737 }
1738 case JSType::JS_API_LINKED_LIST: {
1739 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1740 }
1741 case JSType::JS_API_QUEUE: {
1742 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1743 }
1744 case JSType::JS_API_DEQUE: {
1745 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1746 }
1747 case JSType::JS_API_STACK: {
1748 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1749 }
1750 case JSType::JS_API_PLAIN_ARRAY: {
1751 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1752 }
1753 case JSType::JS_API_VECTOR: {
1754 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1755 }
1756 case JSType::JS_API_BITVECTOR: {
1757 return JSAPIBitVector::GetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1758 }
1759 default: {
1760 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1761 }
1762 }
1763 } else {
1764 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1765 }
1766 return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1767 }
1768
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1769 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1770 const JSHandle<JSTaggedValue> &key,
1771 const JSHandle<JSTaggedValue> &value)
1772 {
1773 if (key->IsInteger()) {
1774 auto *hclass = obj->GetTaggedObject()->GetClass();
1775 JSType jsType = hclass->GetObjectType();
1776 switch (jsType) {
1777 case JSType::JS_API_ARRAY_LIST: {
1778 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1779 }
1780 case JSType::JS_API_LIST: {
1781 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1782 }
1783 case JSType::JS_API_LINKED_LIST: {
1784 JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1785 return true;
1786 }
1787 case JSType::JS_API_QUEUE: {
1788 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1789 }
1790 case JSType::JS_API_DEQUE: {
1791 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1792 }
1793 case JSType::JS_API_STACK: {
1794 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1795 }
1796 case JSType::JS_API_PLAIN_ARRAY: {
1797 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1798 }
1799 case JSType::JS_API_VECTOR: {
1800 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1801 }
1802 case JSType::JS_API_BITVECTOR: {
1803 return JSAPIBitVector::SetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key, value);
1804 }
1805 default: {
1806 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1807 }
1808 }
1809 } else {
1810 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1811 }
1812 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1813 }
1814
1815 } // namespace panda::ecmascript
1816