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 {
85 DISALLOW_GARBAGE_COLLECTION;
86 if (tagged.IsInt() || tagged.IsDouble()) {
87 return JSTaggedNumber(tagged);
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 if (tagged.IsString()) {
106 return StringToNumber(tagged);
107 }
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->IsArrayPrototypeChangedGuardiansInvalid() &&
357 !GetTaggedObject()->GetClass()->IsJSArrayPrototypeModifiedFromBitField();
358 }
359
IsStableJSArguments(JSThread * thread) const360 bool JSTaggedValue::IsStableJSArguments(JSThread *thread) const
361 {
362 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArguments() &&
363 !thread->IsArrayPrototypeChangedGuardiansInvalid();
364 }
365
IsTaggedArray() const366 bool JSTaggedValue::IsTaggedArray() const
367 {
368 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTaggedArray();
369 }
370
IsJSProxy() const371 bool JSTaggedValue::IsJSProxy() const
372 {
373 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSProxy();
374 }
375
IsGeneratorObject() const376 bool JSTaggedValue::IsGeneratorObject() const
377 {
378 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorObject();
379 }
380
IsGeneratorContext() const381 bool JSTaggedValue::IsGeneratorContext() const
382 {
383 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorContext();
384 }
385
WithinInt32(bool acceptsNegativeZero) const386 bool JSTaggedValue::WithinInt32(bool acceptsNegativeZero) const
387 {
388 if (IsInt()) {
389 return true;
390 }
391 if (!IsDouble()) {
392 return false;
393 }
394 double doubleValue = GetDouble();
395 if (base::bit_cast<int64_t>(doubleValue) == base::bit_cast<int64_t>(-0.0)) {
396 return acceptsNegativeZero;
397 }
398 // NaN and INF -> 0
399 int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
400 return doubleValue == static_cast<double>(intvalue);
401 }
402
IsZero() const403 bool JSTaggedValue::IsZero() const
404 {
405 if (GetRawData() == VALUE_ZERO) {
406 return true;
407 }
408 if (IsDouble()) {
409 const double limit = 1e-8;
410 return (std::abs(GetDouble() - 0.0) <= limit);
411 }
412 return false;
413 }
414
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)415 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
416 {
417 if (x->IsNumber()) {
418 return EqualNumber(thread, x, y);
419 }
420
421 if (x->IsString()) {
422 return EqualString(thread, x, y);
423 }
424
425 if (x->IsBoolean()) {
426 JSTaggedNumber xNumber = ToNumber(thread, x);
427 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
428 return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
429 }
430
431 if (x->IsSymbol()) {
432 return EqualSymbol(thread, x, y);
433 }
434
435 if (x->IsBigInt()) {
436 return EqualBigInt(thread, x, y);
437 }
438
439 if (x->IsHeapObject()) {
440 return EqualHeapObject(thread, x, y);
441 }
442
443 return EqualNullOrUndefined(x, y);
444 }
445
EqualNumber(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)446 bool JSTaggedValue::EqualNumber(JSThread *thread, const JSHandle<JSTaggedValue> &x,
447 const JSHandle<JSTaggedValue> &y)
448 {
449 if (y->IsNumber()) {
450 return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
451 }
452 if (y->IsString()) {
453 JSTaggedNumber yNumber = ToNumber(thread, y);
454 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
455 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
456 }
457 if (y->IsBoolean()) {
458 JSTaggedNumber yNumber = ToNumber(thread, y);
459 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
460 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
461 }
462 if (y->IsBigInt()) {
463 return Equal(thread, y, x);
464 }
465 if (y->IsECMAObject()) {
466 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
467 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
468 return Equal(thread, x, yPrimitive);
469 }
470 return false;
471 }
472
EqualString(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)473 bool JSTaggedValue::EqualString(JSThread *thread, const JSHandle<JSTaggedValue> &x,
474 const JSHandle<JSTaggedValue> &y)
475 {
476 if (y->IsString()) {
477 return EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(),
478 JSHandle<EcmaString>(x),
479 JSHandle<EcmaString>(y));
480 }
481 if (y->IsNumber()) {
482 JSTaggedNumber xNumber = ToNumber(thread, x);
483 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
484 return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
485 }
486 if (y->IsBoolean()) {
487 JSTaggedNumber xNumber = ToNumber(thread, x);
488 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
489 JSTaggedNumber yNumber = ToNumber(thread, y);
490 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
491 return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
492 }
493 if (y->IsBigInt()) {
494 return Equal(thread, y, x);
495 }
496 if (y->IsECMAObject()) {
497 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
498 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
499 return Equal(thread, x, yPrimitive);
500 }
501 return false;
502 }
503
EqualSymbol(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)504 bool JSTaggedValue::EqualSymbol(JSThread *thread, const JSHandle<JSTaggedValue> &x,
505 const JSHandle<JSTaggedValue> &y)
506 {
507 if (y->IsSymbol()) {
508 return x.GetTaggedValue() == y.GetTaggedValue();
509 }
510 if (y->IsBigInt() || y->IsString()) {
511 return false;
512 }
513 if (y->IsECMAObject()) {
514 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
515 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
516 return Equal(thread, x, yPrimitive);
517 }
518 return false;
519 }
520
EqualBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)521 bool JSTaggedValue::EqualBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &x,
522 const JSHandle<JSTaggedValue> &y)
523 {
524 if (y->IsBigInt()) {
525 return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
526 }
527 if (y->IsString()) {
528 JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
529 if (!yNumber->IsBigInt()) {
530 return false;
531 }
532 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
533 }
534 if (y->IsBoolean()) {
535 JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
536 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
537 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
538 }
539 if (y->IsNumber()) {
540 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
541 return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
542 }
543 if (y->IsECMAObject()) {
544 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
545 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
546 return Equal(thread, x, yPrimitive);
547 }
548 return false;
549 }
550
EqualHeapObject(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)551 bool JSTaggedValue::EqualHeapObject(JSThread *thread, const JSHandle<JSTaggedValue> &x,
552 const JSHandle<JSTaggedValue> &y)
553 {
554 if (y->IsHeapObject()) {
555 // if same type, must call Type::StrictEqual()
556 JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
557 JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
558 if (xType == yType) {
559 return StrictEqual(thread, x, y);
560 }
561 }
562 if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
563 if (x->IsECMAObject()) {
564 JSHandle<JSTaggedValue> xPrimitive(thread, ToPrimitive(thread, x));
565 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
566 return Equal(thread, xPrimitive, y);
567 }
568 }
569 return false;
570 }
571
EqualNullOrUndefined(const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)572 bool JSTaggedValue::EqualNullOrUndefined(const JSHandle<JSTaggedValue> &x,
573 const JSHandle<JSTaggedValue> &y)
574 {
575 if (x->IsNull() && y->IsNull()) {
576 return true;
577 }
578 if (x->IsUndefined() && y->IsUndefined()) {
579 return true;
580 }
581 if (x->IsNull() && y->IsUndefined()) {
582 return true;
583 }
584 if (x->IsUndefined() && y->IsNull()) {
585 return true;
586 }
587 return false;
588 }
589
590 static const uint32_t POWERS_OF_10[] = {
591 1,
592 10,
593 100,
594 1000,
595 10 * 1000,
596 100 * 1000,
597 1000 * 1000,
598 10 * 1000 * 1000,
599 100 * 1000 * 1000,
600 1000 * 1000 * 1000,
601 };
602
IntLexicographicCompare(JSTaggedValue x,JSTaggedValue y)603 int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
604 {
605 ASSERT(x.IsInt() && y.IsInt());
606 int xValue = x.GetInt();
607 int yValue = y.GetInt();
608 if (xValue == yValue) {
609 return 0;
610 }
611 if (xValue == 0 || yValue == 0) {
612 return xValue > yValue ? 1 : -1;
613 }
614 uint32_t unsignedX = static_cast<uint32_t>(xValue);
615 uint32_t unsignedY = static_cast<uint32_t>(yValue);
616 if (yValue > 0) {
617 if (xValue < 0) {
618 return -1;
619 }
620 } else {
621 if (xValue > 0) {
622 return 1;
623 }
624 unsignedX = static_cast<uint32_t>(base::NegateWithWraparound(xValue));
625 unsignedY = static_cast<uint32_t>(base::NegateWithWraparound(yValue));
626 }
627 int xLog2 = 31 - __builtin_clz(unsignedX);
628 int xDigit = ((xLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
629 xDigit -= unsignedX < POWERS_OF_10[xDigit];
630
631 int yLog2 = 31 - __builtin_clz(unsignedY);
632 int yDigit = ((yLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
633 yDigit -= unsignedY < POWERS_OF_10[yDigit];
634
635 int res = 0;
636 if (xDigit > yDigit) {
637 // X has fewer digits. We would like to simply scale up X but that
638 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
639 // be scaled up to 9_000_000_000. So we scale up by the next
640 // smallest power and scale down Y to drop one digit. It is OK to
641 // drop one digit from the longer integer since the final digit is
642 // past the length of the shorter integer.
643 unsignedY *= POWERS_OF_10[xDigit - yDigit - 1];
644 unsignedX /= 10; // 10 : Decimal
645 res = 1;
646 }
647 if (yDigit > xDigit) {
648 unsignedX *= POWERS_OF_10[yDigit - xDigit - 1];
649 unsignedY /= 10; // 10 : Decimal
650 res = -1;
651 }
652 if (unsignedX > unsignedY) {
653 return 1;
654 }
655
656 if (unsignedY > unsignedX) {
657 return -1;
658 }
659 return res;
660 }
661
DoubleLexicographicCompare(JSTaggedValue x,JSTaggedValue y)662 int JSTaggedValue::DoubleLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
663 {
664 ASSERT(x.IsDouble() && y.IsDouble());
665 CString xStr = base::NumberHelper::DoubleToCString(x.GetDouble());
666 CString yStr = base::NumberHelper::DoubleToCString(y.GetDouble());
667 return xStr.compare(yStr);
668 }
669
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)670 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
671 const JSHandle<JSTaggedValue> &y)
672 {
673 if (x->IsDate() && y->IsDate()) {
674 double timeX = JSDate::Cast(x->GetTaggedObject())->GetTimeValue().GetDouble();
675 double timeY = JSDate::Cast(y->GetTaggedObject())->GetTimeValue().GetDouble();
676 return StrictNumberCompare(timeX, timeY);
677 }
678 JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
679 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
680 JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
681 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
682 if (primX->IsString() && primY->IsString()) {
683 auto xHandle = JSHandle<EcmaString>(primX);
684 auto yHandle = JSHandle<EcmaString>(primY);
685 int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
686 if (result < 0) {
687 return ComparisonResult::LESS;
688 }
689 if (result == 0) {
690 return ComparisonResult::EQUAL;
691 }
692 return ComparisonResult::GREAT;
693 }
694 if (primX->IsBigInt()) {
695 if (primY->IsNumber()) {
696 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
697 return BigInt::CompareWithNumber(bigint, primY);
698 } else if (primY->IsString()) {
699 JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
700 if (!bigY->IsBigInt()) {
701 return ComparisonResult::UNDEFINED;
702 }
703 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
704 } else {
705 JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
706 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
707 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
708 }
709 }
710 if (primY->IsBigInt()) {
711 ComparisonResult res = Compare(thread, primY, primX);
712 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
713 if (res == ComparisonResult::GREAT) {
714 return ComparisonResult::LESS;
715 } else if (res == ComparisonResult::LESS) {
716 return ComparisonResult::GREAT;
717 }
718 return res;
719 }
720 double resultX = 0;
721 double resultY = 0;
722 if (primX->IsNumber()) {
723 resultX = primX->GetNumber();
724 } else {
725 JSTaggedNumber xNumber = ToNumber(thread, x);
726 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
727 resultX = xNumber.GetNumber();
728 }
729 if (primY->IsNumber()) {
730 resultY = primY->GetNumber();
731 } else {
732 JSTaggedNumber yNumber = ToNumber(thread, y);
733 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
734 resultY = yNumber.GetNumber();
735 }
736 return StrictNumberCompare(resultX, resultY);
737 }
738
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)739 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
740 {
741 if (x.IsNumber() && y.IsNumber()) {
742 return true;
743 }
744 if (x.IsBoolean() && y.IsBoolean()) {
745 return true;
746 }
747 if (x.IsString() && y.IsString()) {
748 return true;
749 }
750 if (x.IsHeapObject() && y.IsHeapObject()) {
751 return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
752 }
753
754 return false;
755 }
756
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)757 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
758 PreferredPrimitiveType type)
759 {
760 if (tagged->IsECMAObject()) {
761 EcmaVM *vm = thread->GetEcmaVM();
762 JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
763
764 JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
765 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
766 if (!exoticToprim->IsUndefined()) {
767 JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
768 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
769 EcmaRuntimeCallInfo *info =
770 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
771 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
772 info->SetCallArg(value);
773 JSTaggedValue valueResult = JSFunction::Call(info);
774 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
775 if (!valueResult.IsECMAObject()) {
776 return valueResult;
777 }
778 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert object to primitive value",
779 JSTaggedValue::Exception());
780 } else {
781 type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
782 return OrdinaryToPrimitive(thread, tagged, type);
783 }
784 }
785 return tagged.GetTaggedValue();
786 }
787
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)788 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
789 PreferredPrimitiveType type)
790 {
791 static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
792 ASSERT(tagged->IsECMAObject());
793 auto globalConst = thread->GlobalConstants();
794 for (uint8_t i = 0; i < 2; i++) { // 2: 2 means value has 2 target types, string or value.
795 JSHandle<JSTaggedValue> keyString;
796 if ((static_cast<uint8_t>(type) ^ i) != 0) {
797 keyString = globalConst->GetHandledToStringString();
798 } else {
799 keyString = globalConst->GetHandledValueOfString();
800 }
801 JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
802 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
803 if (entryfunc->IsCallable()) {
804 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
805 EcmaRuntimeCallInfo *info =
806 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
807 JSTaggedValue valueResult = JSFunction::Call(info);
808 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
809 if (!valueResult.IsECMAObject()) {
810 return valueResult;
811 }
812 }
813 }
814 DumpExceptionObject(thread, tagged);
815 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
816 }
817
ToString(JSThread * thread,JSTaggedValue val)818 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
819 {
820 JSHandle<JSTaggedValue> tagged(thread, val);
821 return ToString(thread, tagged);
822 }
823
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)824 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
825 {
826 if (tagged->IsString()) {
827 return JSHandle<EcmaString>(tagged);
828 }
829 auto globalConst = thread->GlobalConstants();
830 if (tagged->IsSpecial()) {
831 switch (tagged->GetRawData()) {
832 case VALUE_UNDEFINED: {
833 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
834 }
835 case VALUE_NULL: {
836 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
837 }
838 case VALUE_TRUE: {
839 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
840 }
841 case VALUE_FALSE: {
842 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
843 }
844 case VALUE_HOLE: {
845 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
846 }
847 default:
848 break;
849 }
850 }
851
852 if (tagged->IsNumber()) {
853 return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
854 }
855
856 if (tagged->IsBigInt()) {
857 JSHandle<BigInt> taggedValue(tagged);
858 return BigInt::ToString(thread, taggedValue);
859 }
860
861 if (tagged->IsNativePointer()) {
862 return NativePointerToString(thread, tagged);
863 }
864
865 auto emptyStr = globalConst->GetHandledEmptyString();
866 if (tagged->IsECMAObject()) {
867 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
868 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
869 return ToString(thread, primValue);
870 }
871 DumpExceptionObject(thread, tagged);
872 // Already Include Symbol
873 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
874 }
875
NativePointerToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)876 JSHandle<EcmaString> JSTaggedValue::NativePointerToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
877 {
878 JSHandle<JSNativePointer> taggedHandle(tagged);
879 std::stringstream stringstream;
880 stringstream << std::hex << taggedHandle->GetExternalPointer();
881 std::string nativePtrStr = "[External: " + stringstream.str() + "]";
882
883 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
884 return factory->NewFromASCII(nativePtrStr);
885 }
886
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)887 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
888 {
889 if (tagged->IsNumber()) {
890 return tagged.GetTaggedValue();
891 }
892
893 if (tagged->IsString()) {
894 JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
895 if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), JSHandle<EcmaString>(tagged), str)) {
896 return JSTaggedValue(-0.0);
897 }
898 JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
899 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
900 if (SameValue(ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
901 return tmp.GetTaggedValue();
902 }
903 }
904 return JSTaggedValue::Undefined();
905 }
906
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)907 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
908 {
909 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
910 if (tagged->IsInt() || tagged->IsDouble()) {
911 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
912 }
913
914 switch (tagged->GetRawData()) {
915 case JSTaggedValue::VALUE_UNDEFINED: {
916 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
917 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
918 }
919 case JSTaggedValue::VALUE_HOLE: {
920 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
921 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
922 }
923 case JSTaggedValue::VALUE_NULL: {
924 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
925 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
926 }
927 case JSTaggedValue::VALUE_TRUE:
928 case JSTaggedValue::VALUE_FALSE: {
929 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
930 }
931 default: {
932 break;
933 }
934 }
935
936 if (tagged->IsECMAObject()) {
937 return JSHandle<JSObject>::Cast(tagged);
938 }
939 if (tagged->IsSymbol()) {
940 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
941 }
942 if (tagged->IsString()) {
943 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
944 }
945 if (tagged->IsBigInt()) {
946 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
947 }
948 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
949 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
950 }
951
952 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)953 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
954 const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
955 {
956 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
957 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
958 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
959 std::string message = "Cannot read property ";
960 message.append(keyStr).append(" of ").append(objStr);
961 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
962 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
963 }
964 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
965
966 if (obj->IsJSProxy()) {
967 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
968 }
969 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
970 return JSTypedArray::GetProperty(thread, obj, key);
971 }
972 if (obj->IsModuleNamespace()) {
973 return ModuleNamespace::GetProperty(thread, obj, key);
974 }
975
976 if (obj->IsSpecialContainer()) {
977 return GetJSAPIProperty(thread, obj, key);
978 }
979
980 return JSObject::GetProperty(thread, obj, key, sCheckMode);
981 }
982
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)983 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
984 {
985 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
986 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
987 std::string message = "Cannot read property ";
988 message.append(ToCString(key)).append(" of ").append(objStr);
989 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
990 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
991 }
992
993 if (obj->IsJSProxy()) {
994 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
995 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
996 }
997
998 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
999 return JSTypedArray::GetProperty(thread, obj, key);
1000 }
1001
1002 if (obj->IsSpecialContainer()) {
1003 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1004 return GetJSAPIProperty(thread, obj, keyHandle);
1005 }
1006
1007 return JSObject::GetProperty(thread, obj, key);
1008 }
1009
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)1010 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1011 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
1012 {
1013 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1014 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
1015 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
1016 std::string message = "Cannot read property ";
1017 message.append(keyStr).append(" of ").append(objStr);
1018 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
1019 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
1020 }
1021 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1022
1023 if (obj->IsJSProxy()) {
1024 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
1025 }
1026 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1027 return JSTypedArray::GetProperty(thread, obj, key, receiver);
1028 }
1029
1030 if (obj->IsSpecialContainer()) {
1031 return GetJSAPIProperty(thread, obj, key);
1032 }
1033
1034 return JSObject::GetProperty(thread, obj, key, receiver);
1035 }
1036
1037 // 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)1038 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1039 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow,
1040 SCheckMode checkMode)
1041 {
1042 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1043 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1044 }
1045
1046 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1047
1048 // 4. Let success be O.[[Set]](P, V, O).
1049 bool success = false;
1050 if (obj->IsJSProxy()) {
1051 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
1052 } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1053 success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
1054 } else if (obj->IsModuleNamespace()) {
1055 success = ModuleNamespace::SetProperty(thread, mayThrow);
1056 } else if (obj->IsSpecialContainer()) {
1057 success = SetJSAPIProperty(thread, obj, key, value);
1058 } else {
1059 success = JSObject::SetProperty(thread, obj, key, value, mayThrow, checkMode);
1060 }
1061 // 5. ReturnIfAbrupt(success).
1062 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1063 // 6. If success is false and Throw is true, throw a TypeError exception.
1064 // have done in JSObject::SetPropert.
1065 return success;
1066 }
1067
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)1068 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
1069 const JSHandle<JSTaggedValue> &value, bool mayThrow)
1070 {
1071 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1072 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1073 }
1074
1075 // 4. Let success be O.[[Set]](P, V, O).
1076 bool success = false;
1077 if (obj->IsJSProxy()) {
1078 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1079 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
1080 } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1081 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1082 success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
1083 } else if (obj->IsModuleNamespace()) {
1084 success = ModuleNamespace::SetProperty(thread, mayThrow);
1085 } else if (obj->IsSpecialContainer()) {
1086 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1087 success = SetJSAPIProperty(thread, obj, keyHandle, value);
1088 } else {
1089 success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
1090 }
1091 // 5. ReturnIfAbrupt(success).
1092 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1093 // 6. If success is false and Throw is true, throw a TypeError exception.
1094 // have done in JSObject::SetPropert.
1095 return success;
1096 }
1097
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)1098 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1099 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
1100 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
1101 {
1102 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1103 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1104 }
1105
1106 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1107
1108 // 4. Let success be O.[[Set]](P, V, O).
1109 bool success = false;
1110 if (obj->IsJSProxy()) {
1111 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
1112 } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1113 success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
1114 } else if (obj->IsModuleNamespace()) {
1115 success = ModuleNamespace::SetProperty(thread, mayThrow);
1116 } else if (obj->IsSpecialContainer()) {
1117 success = SetJSAPIProperty(thread, obj, key, value);
1118 } else {
1119 success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
1120 }
1121 // 5. ReturnIfAbrupt(success).
1122 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1123 // 6. If success is false and Throw is true, throw a TypeError exception.
1124 // have done in JSObject::SetPropert.
1125 return success;
1126 }
1127
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1128 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1129 const JSHandle<JSTaggedValue> &key)
1130 {
1131 if (obj->IsJSProxy()) {
1132 return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
1133 }
1134
1135 if (obj->IsModuleNamespace()) {
1136 return ModuleNamespace::DeleteProperty(thread, obj, key);
1137 }
1138
1139 if (obj->IsTypedArray()) {
1140 return JSTypedArray::DeleteProperty(thread, obj, key);
1141 }
1142
1143 if (obj->IsSpecialContainer()) {
1144 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
1145 }
1146
1147 return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
1148 }
1149
1150 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1151 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1152 const JSHandle<JSTaggedValue> &key)
1153 {
1154 if (!obj->IsECMAObject()) {
1155 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
1156 }
1157 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1158
1159 // 3. Let success be O.[[Delete]](P).
1160 bool success = DeleteProperty(thread, obj, key);
1161
1162 // 4. ReturnIfAbrupt(success).
1163 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1164 // 5. If success is false, throw a TypeError exception
1165 if (!success) {
1166 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
1167 }
1168 return success;
1169 }
1170
1171 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1172 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1173 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
1174 {
1175 // 1. Assert: Type(O) is Object.
1176 // 2. Assert: IsPropertyKey(P) is true.
1177 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1178 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1179 // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
1180 bool success = DefineOwnProperty(thread, obj, key, desc);
1181 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1182 // 4. If success is false, throw a TypeError exception.
1183 if (!success) {
1184 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot define property", false);
1185 }
1186 return success;
1187 }
1188
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc,SCheckMode sCheckMode)1189 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1190 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
1191 SCheckMode sCheckMode)
1192 {
1193 if (obj->IsJSArray()) {
1194 return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1195 }
1196
1197 if (obj->IsJSSharedArray()) {
1198 return JSSharedArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc, sCheckMode);
1199 }
1200
1201 if (obj->IsJSProxy()) {
1202 return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1203 }
1204
1205 if (obj->IsTypedArray()) {
1206 return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
1207 }
1208
1209 if (obj->IsModuleNamespace()) {
1210 return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
1211 }
1212
1213 if (obj->IsSpecialContainer()) {
1214 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
1215 }
1216
1217 return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1218 }
1219
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1220 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1221 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1222 {
1223 if (obj->IsJSProxy()) {
1224 return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1225 }
1226 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1227 return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
1228 }
1229 if (obj->IsModuleNamespace()) {
1230 return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
1231 }
1232 if (obj->IsSpecialContainer()) {
1233 return GetContainerProperty(thread, obj, key, desc);
1234 }
1235 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1236 }
1237
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto,bool isChangeProto)1238 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1239 const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
1240 {
1241 if (obj->IsJSShared() || proto->IsJSShared()) {
1242 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetProtoWithSendable), false);
1243 }
1244
1245 if (obj->IsJSProxy()) {
1246 return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
1247 }
1248 if (obj->IsModuleNamespace()) {
1249 return ModuleNamespace::SetPrototype(obj, proto);
1250 }
1251 if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
1252 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
1253 }
1254 if (obj->IsJSFunction() && proto->IsJSFunction()) {
1255 JSHandle<JSFunction> objFunc = JSHandle<JSFunction>::Cast(obj);
1256 JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass());
1257 if (objProtoOrHClass.IsJSHClass() && objFunc->IsDerivedConstructor()) {
1258 JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
1259 objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype());
1260 }
1261 }
1262
1263 return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto, isChangeProto);
1264 }
1265
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1266 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1267 {
1268 if (!obj->IsECMAObject()) {
1269 DumpExceptionObject(thread, obj);
1270 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
1271 }
1272 if (obj->IsJSProxy()) {
1273 return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
1274 }
1275 return JSObject::GetPrototype(JSHandle<JSObject>(obj));
1276 }
1277
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1278 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1279 {
1280 if (obj->IsJSProxy()) {
1281 return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
1282 }
1283 if (obj->IsModuleNamespace()) {
1284 return ModuleNamespace::PreventExtensions();
1285 }
1286 return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
1287 }
1288
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1289 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1290 {
1291 if (obj->IsJSProxy()) {
1292 return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
1293 }
1294 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1295 return JSTypedArray::OwnPropertyKeys(thread, obj);
1296 }
1297 if (obj->IsSpecialContainer()) {
1298 return GetOwnContainerPropertyKeys(thread, obj);
1299 }
1300 if (obj->IsModuleNamespace()) {
1301 return ModuleNamespace::OwnPropertyKeys(thread, obj);
1302 }
1303 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1304 }
1305
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)1306 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
1307 const JSHandle<JSTaggedValue> &obj, uint32_t filter)
1308 {
1309 if (obj->IsJSProxy()) {
1310 return JSProxy::GetAllPropertyKeys(thread, JSHandle<JSProxy>(obj), filter);
1311 }
1312 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1313 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
1314 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1315 }
1316 if (obj->IsSpecialContainer()) {
1317 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
1318 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1319 }
1320 if (obj->IsModuleNamespace()) {
1321 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
1322 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1323 }
1324 return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
1325 }
1326
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1327 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1328 {
1329 ASSERT(!obj->IsJSProxy());
1330 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1331 return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
1332 }
1333 if (obj->IsSpecialContainer()) {
1334 return GetOwnContainerEnumPropertyKeys(thread, obj);
1335 }
1336 if (obj->IsModuleNamespace()) {
1337 return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
1338 }
1339 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1340 }
1341
1342 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1343 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1344 const JSHandle<JSTaggedValue> &key)
1345 {
1346 if (obj->IsJSProxy()) {
1347 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
1348 }
1349 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1350 return JSTypedArray::HasProperty(thread, obj, key);
1351 }
1352 if (obj->IsModuleNamespace()) {
1353 return ModuleNamespace::HasProperty(thread, obj, key);
1354 }
1355 if (obj->IsSpecialContainer()) {
1356 return HasContainerProperty(thread, obj, key);
1357 }
1358 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1359 }
1360
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)1361 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
1362 {
1363 if (obj->IsJSProxy()) {
1364 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1365 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1366 }
1367 if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1368 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1369 return JSTypedArray::HasProperty(thread, obj, keyHandle);
1370 }
1371 if (obj->IsSpecialContainer()) {
1372 return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
1373 }
1374 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1375 }
1376
1377 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1378 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1379 const JSHandle<JSTaggedValue> &key)
1380 {
1381 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1382
1383 PropertyDescriptor desc(thread);
1384 return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
1385 }
1386
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)1387 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1388 {
1389 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1390
1391 PropertyDescriptor desc(thread);
1392 return JSObject::GlobalGetOwnProperty(thread, key, desc);
1393 }
1394
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1395 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1396 {
1397 // 1. If v is an Object, return true.
1398 if (tagged->IsECMAObject()) {
1399 return true;
1400 }
1401 // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
1402 if (tagged->IsSymbol()) {
1403 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1404 auto *table = env->GetRegisterSymbols().GetObject<SymbolTable>();
1405 JSTaggedValue key = table->FindSymbol(tagged.GetTaggedValue());
1406 if (key.IsUndefined()) {
1407 return true;
1408 }
1409 }
1410 // 3. Return false.
1411 return false;
1412 }
1413
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1414 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1415 {
1416 if (tagged->IsInt() && tagged->GetInt() >= 0) {
1417 return JSTaggedNumber(tagged.GetTaggedValue());
1418 }
1419 if (tagged->IsUndefined()) {
1420 return JSTaggedNumber(0);
1421 }
1422 JSTaggedNumber integerIndex = ToNumber(thread, tagged);
1423 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
1424 if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
1425 return integerIndex;
1426 }
1427 double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
1428 if (len < 0.0 || len > SAFE_NUMBER) {
1429 THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
1430 JSTaggedNumber::Exception());
1431 }
1432 return JSTaggedNumber(len);
1433 }
1434
1435 // 9.4.2.4 ArraySetLength 3 to 7
ToArrayLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,uint32_t * output)1436 bool JSTaggedValue::ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output)
1437 {
1438 // 3. Let newLen be ToUint32(Desc.[[Value]]).
1439 uint32_t newLen = ToUint32(thread, tagged);
1440 // 4. ReturnIfAbrupt(newLen).
1441 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1442
1443 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
1444 JSTaggedNumber numberLen = ToNumber(thread, tagged);
1445 // 6. ReturnIfAbrupt(newLen).
1446 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1447
1448 // 7. If newLen != numberLen, throw a RangeError exception.
1449 if (JSTaggedNumber(newLen) != numberLen) {
1450 THROW_RANGE_ERROR_AND_RETURN(thread, "Not a valid array length", false);
1451 }
1452
1453 *output = newLen;
1454 return true;
1455 }
1456
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1457 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1458 {
1459 #ifdef ENABLE_NEXT_OPTIMIZATION
1460 if (obj->IsECMAObject()) {
1461 return obj;
1462 }
1463 #endif
1464 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1465 if (obj->IsNumber()) {
1466 return JSHandle<JSTaggedValue>(thread,
1467 env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1468 }
1469 if (obj->IsBoolean()) {
1470 return JSHandle<JSTaggedValue>(thread,
1471 env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1472 }
1473 if (obj->IsString()) {
1474 return JSHandle<JSTaggedValue>(thread,
1475 env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1476 }
1477 if (obj->IsSymbol()) {
1478 return JSHandle<JSTaggedValue>(thread,
1479 env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1480 }
1481 if (obj->IsBigInt()) {
1482 return JSHandle<JSTaggedValue>(thread,
1483 env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1484 }
1485 return obj;
1486 }
1487
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1488 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1489 {
1490 if (obj->IsUndefined()) {
1491 return JSTaggedValue::Undefined();
1492 }
1493
1494 ASSERT(obj->IsECMAObject());
1495 return JSTaggedValue::GetPrototype(thread, obj);
1496 }
1497
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1498 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1499 const JSHandle<JSTaggedValue> &key)
1500 {
1501 auto *hclass = obj->GetTaggedObject()->GetClass();
1502 JSType jsType = hclass->GetObjectType();
1503 switch (jsType) {
1504 case JSType::JS_API_ARRAY_LIST: {
1505 return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
1506 }
1507 case JSType::JS_API_QUEUE: {
1508 return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
1509 }
1510 case JSType::JS_API_PLAIN_ARRAY: {
1511 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1512 }
1513 case JSType::JS_API_DEQUE: {
1514 return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
1515 }
1516 case JSType::JS_API_STACK: {
1517 return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
1518 }
1519 case JSType::JS_API_LIST: {
1520 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1521 return list->Has(key.GetTaggedValue());
1522 }
1523 case JSType::JS_API_LINKED_LIST: {
1524 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1525 return linkedList->Has(key.GetTaggedValue());
1526 }
1527 case JSType::JS_API_HASH_MAP:
1528 case JSType::JS_API_HASH_SET:
1529 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1530 case JSType::JS_API_LIGHT_WEIGHT_SET:
1531 case JSType::JS_API_TREE_MAP:
1532 case JSType::JS_API_TREE_SET: {
1533 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1534 }
1535 case JSType::JS_API_VECTOR: {
1536 return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
1537 }
1538 case JSType::JS_API_BITVECTOR: {
1539 return JSHandle<JSAPIBitVector>::Cast(obj)->Has(key.GetTaggedValue());
1540 }
1541 default: {
1542 LOG_ECMA(FATAL) << "this branch is unreachable";
1543 UNREACHABLE();
1544 }
1545 }
1546 return false;
1547 }
1548
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1549 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1550 {
1551 auto *hclass = obj->GetTaggedObject()->GetClass();
1552 JSType jsType = hclass->GetObjectType();
1553 switch (jsType) {
1554 case JSType::JS_API_ARRAY_LIST: {
1555 return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1556 }
1557 case JSType::JS_API_QUEUE: {
1558 return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1559 }
1560 case JSType::JS_API_PLAIN_ARRAY: {
1561 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1562 }
1563 case JSType::JS_API_DEQUE: {
1564 return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1565 }
1566 case JSType::JS_API_STACK: {
1567 return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1568 }
1569 case JSType::JS_API_LIST: {
1570 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1571 }
1572 case JSType::JS_API_LINKED_LIST: {
1573 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1574 }
1575 case JSType::JS_API_HASH_MAP:
1576 case JSType::JS_API_HASH_SET:
1577 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1578 case JSType::JS_API_LIGHT_WEIGHT_SET:
1579 case JSType::JS_API_TREE_MAP:
1580 case JSType::JS_API_TREE_SET: {
1581 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1582 }
1583 case JSType::JS_API_VECTOR: {
1584 return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1585 }
1586 case JSType::JS_API_BITVECTOR: {
1587 return JSAPIBitVector::OwnKeys(thread, JSHandle<JSAPIBitVector>::Cast(obj));
1588 }
1589 default: {
1590 LOG_ECMA(FATAL) << "this branch is unreachable";
1591 UNREACHABLE();
1592 }
1593 }
1594 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1595 }
1596
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1597 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1598 const JSHandle<JSTaggedValue> &obj)
1599 {
1600 auto *hclass = obj->GetTaggedObject()->GetClass();
1601 JSType jsType = hclass->GetObjectType();
1602 switch (jsType) {
1603 case JSType::JS_API_QUEUE: {
1604 return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1605 }
1606 case JSType::JS_API_DEQUE: {
1607 return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1608 }
1609 case JSType::JS_API_LIST: {
1610 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1611 }
1612 case JSType::JS_API_LINKED_LIST: {
1613 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1614 }
1615 case JSType::JS_API_VECTOR:
1616 case JSType::JS_API_BITVECTOR:
1617 case JSType::JS_API_STACK:
1618 case JSType::JS_API_ARRAY_LIST:
1619 case JSType::JS_API_PLAIN_ARRAY:
1620 case JSType::JS_API_HASH_MAP:
1621 case JSType::JS_API_HASH_SET:
1622 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1623 case JSType::JS_API_LIGHT_WEIGHT_SET:
1624 case JSType::JS_API_TREE_MAP:
1625 case JSType::JS_API_TREE_SET: {
1626 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1627 }
1628 default: {
1629 UNREACHABLE();
1630 }
1631 }
1632 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1633 }
1634
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1635 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1636 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1637 {
1638 if (key->IsInteger()) {
1639 auto *hclass = obj->GetTaggedObject()->GetClass();
1640 JSType jsType = hclass->GetObjectType();
1641 switch (jsType) {
1642 case JSType::JS_API_ARRAY_LIST: {
1643 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1644 }
1645 case JSType::JS_API_QUEUE: {
1646 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1647 }
1648 case JSType::JS_API_DEQUE: {
1649 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1650 }
1651 case JSType::JS_API_STACK: {
1652 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1653 }
1654 case JSType::JS_API_LIST: {
1655 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1656 }
1657 case JSType::JS_API_LINKED_LIST: {
1658 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1659 }
1660 case JSType::JS_API_PLAIN_ARRAY: {
1661 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1662 }
1663 case JSType::JS_API_VECTOR: {
1664 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1665 }
1666 case JSType::JS_API_BITVECTOR: {
1667 return JSAPIBitVector::GetOwnProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1668 }
1669 default: {
1670 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1671 }
1672 }
1673 } else {
1674 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1675 }
1676 return false;
1677 }
1678
StringToNumber(JSTaggedValue tagged)1679 JSTaggedNumber JSTaggedValue::StringToNumber(JSTaggedValue tagged)
1680 {
1681 EcmaStringAccessor strAccessor(tagged);
1682 size_t strLen = strAccessor.GetLength();
1683 if (strLen == 0) {
1684 return JSTaggedNumber(0);
1685 }
1686 if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) {
1687 uint32_t index;
1688 // fast path: get integer from string's hash value
1689 if (strAccessor.TryToGetInteger(&index)) {
1690 return JSTaggedNumber(index);
1691 }
1692 Span<const uint8_t> str = strAccessor.FastToUtf8Span();
1693 if (strAccessor.GetLength() == 0) {
1694 return JSTaggedNumber(0);
1695 }
1696 auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), tagged);
1697 if (isSuccess) {
1698 return result;
1699 }
1700 }
1701 CVector<uint8_t> buf;
1702 Span<const uint8_t> str = strAccessor.ToUtf8Span(buf);
1703 double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
1704 base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
1705 return JSTaggedNumber(d);
1706 }
1707
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1708 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1709 {
1710 // 1. Let primValue be ? ToPrimitive(value, number)
1711 JSTaggedValue primValue = ToPrimitive(thread, tagged, PREFER_NUMBER);
1712 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1713 // 2. If Type(primValue) is BigInt, return primValue.
1714 if (primValue.IsBigInt()) {
1715 return JSHandle<JSTaggedValue>(thread, primValue);
1716 }
1717 // 3. Return ? ToNumber(primValue).
1718 JSTaggedNumber number = ToNumber(thread, primValue);
1719 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1720 JSHandle<JSTaggedValue> value(thread, number);
1721 return value;
1722 }
1723
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1724 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1725 const JSHandle<JSTaggedValue> &key)
1726 {
1727 if (key->IsInteger()) {
1728 auto *hclass = obj->GetTaggedObject()->GetClass();
1729 JSType jsType = hclass->GetObjectType();
1730 switch (jsType) {
1731 case JSType::JS_API_ARRAY_LIST: {
1732 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1733 }
1734 case JSType::JS_API_LIST: {
1735 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1736 }
1737 case JSType::JS_API_LINKED_LIST: {
1738 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1739 }
1740 case JSType::JS_API_QUEUE: {
1741 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1742 }
1743 case JSType::JS_API_DEQUE: {
1744 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1745 }
1746 case JSType::JS_API_STACK: {
1747 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1748 }
1749 case JSType::JS_API_PLAIN_ARRAY: {
1750 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1751 }
1752 case JSType::JS_API_VECTOR: {
1753 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1754 }
1755 case JSType::JS_API_BITVECTOR: {
1756 return JSAPIBitVector::GetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1757 }
1758 default: {
1759 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1760 }
1761 }
1762 } else {
1763 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1764 }
1765 return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1766 }
1767
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1768 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1769 const JSHandle<JSTaggedValue> &key,
1770 const JSHandle<JSTaggedValue> &value)
1771 {
1772 if (key->IsInteger()) {
1773 auto *hclass = obj->GetTaggedObject()->GetClass();
1774 JSType jsType = hclass->GetObjectType();
1775 switch (jsType) {
1776 case JSType::JS_API_ARRAY_LIST: {
1777 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1778 }
1779 case JSType::JS_API_LIST: {
1780 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1781 }
1782 case JSType::JS_API_LINKED_LIST: {
1783 JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1784 return true;
1785 }
1786 case JSType::JS_API_QUEUE: {
1787 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1788 }
1789 case JSType::JS_API_DEQUE: {
1790 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1791 }
1792 case JSType::JS_API_STACK: {
1793 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1794 }
1795 case JSType::JS_API_PLAIN_ARRAY: {
1796 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1797 }
1798 case JSType::JS_API_VECTOR: {
1799 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1800 }
1801 case JSType::JS_API_BITVECTOR: {
1802 return JSAPIBitVector::SetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key, value);
1803 }
1804 default: {
1805 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1806 }
1807 }
1808 } else {
1809 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1810 }
1811 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1812 }
1813
DumpExceptionObject(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1814 void JSTaggedValue::DumpExceptionObject(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1815 {
1816 if (thread->GetEcmaVM()->GetJSOptions().EnableExceptionBacktrace()) {
1817 DesensitizedDump(obj);
1818 }
1819 }
1820
DesensitizedDump(const JSHandle<JSTaggedValue> & obj)1821 void JSTaggedValue::DesensitizedDump(const JSHandle<JSTaggedValue> &obj)
1822 {
1823 std::ostringstream oss;
1824 obj->Dump(oss, true);
1825 std::regex reg("0x[0-9a-fA-F]+");
1826 std::string sensitiveStr = std::regex_replace(oss.str(), reg, "");
1827 LOG_ECMA(ERROR) << "DumpExceptionObject: " << sensitiveStr;
1828 }
1829
PublishSharedValueSlow(JSThread * thread,JSHandle<JSTaggedValue> value)1830 JSHandle<JSTaggedValue> JSTaggedValue::PublishSharedValueSlow(JSThread *thread, JSHandle<JSTaggedValue> value)
1831 {
1832 SharedValuePublishGuard guard;
1833
1834 ASSERT(value->IsTreeString());
1835 EcmaString *flatStr = EcmaStringAccessor::Flatten(thread->GetEcmaVM(), JSHandle<EcmaString>(value));
1836 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(flatStr));
1837 }
1838
GetStringKeyHashCode() const1839 uint32_t JSTaggedValue::GetStringKeyHashCode() const
1840 {
1841 ASSERT(IsString());
1842 return EcmaStringAccessor(GetTaggedObject()).GetHashcode();
1843 }
1844 } // namespace panda::ecmascript
1845