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