1 /*
2 * Copyright (c) 2021-2022 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_macros.h"
19 #include "ecmascript/ecma_vm.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_deque.h"
24 #include "ecmascript/js_api/js_api_lightweightset.h"
25 #include "ecmascript/js_api/js_api_lightweightmap.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_array.h"
33 #include "ecmascript/js_handle.h"
34 #include "ecmascript/js_object-inl.h"
35 #include "ecmascript/js_primitive_ref.h"
36 #include "ecmascript/js_proxy.h"
37 #include "ecmascript/js_tagged_value-inl.h"
38 #include "ecmascript/js_thread.h"
39 #include "ecmascript/js_typed_array.h"
40 #include "ecmascript/module/js_module_namespace.h"
41 #include "ecmascript/tagged_array.h"
42 #include "ecmascript/object_factory.h"
43
44 namespace panda::ecmascript {
GetTypeString(JSThread * thread,PreferredPrimitiveType type)45 JSHandle<EcmaString> GetTypeString(JSThread *thread, PreferredPrimitiveType type)
46 {
47 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
48 if (type == NO_PREFERENCE) {
49 return JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString());
50 }
51 if (type == PREFER_NUMBER) {
52 return JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString());
53 }
54 return JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString());
55 }
56
ToPropertyKey(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)57 JSHandle<JSTaggedValue> JSTaggedValue::ToPropertyKey(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
58 {
59 if (tagged->IsStringOrSymbol() || tagged->IsNumber()) {
60 return tagged;
61 }
62 JSHandle<JSTaggedValue> key(thread, ToPrimitive(thread, tagged, PREFER_STRING));
63 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
64 if (key->IsSymbol()) {
65 return key;
66 }
67 JSHandle<EcmaString> string = ToString(thread, key);
68 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
69 return JSHandle<JSTaggedValue>::Cast(string);
70 }
71
IsInteger() const72 bool JSTaggedValue::IsInteger() const
73 {
74 if (!IsNumber()) {
75 return false;
76 }
77
78 if (IsInt()) {
79 return true;
80 }
81
82 double thisValue = GetDouble();
83 // If argument is NaN, +∞, or -∞, return false.
84 if (!std::isfinite(thisValue)) {
85 return false;
86 }
87
88 // If floor(abs(argument)) ≠ abs(argument), return false.
89 if (std::floor(std::abs(thisValue)) != std::abs(thisValue)) {
90 return false;
91 }
92
93 return true;
94 }
95
IsJSCOWArray() const96 bool JSTaggedValue::IsJSCOWArray() const
97 {
98 // Elements of JSArray are shared and properties are not yet.
99 return IsJSArray() && JSArray::Cast(GetTaggedObject())->GetElements().IsCOWArray();
100 }
101
WithinInt32() const102 bool JSTaggedValue::WithinInt32() const
103 {
104 if (!IsNumber()) {
105 return false;
106 }
107
108 double doubleValue = GetNumber();
109 if (bit_cast<int64_t>(doubleValue) == bit_cast<int64_t>(-0.0)) {
110 return false;
111 }
112
113 int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
114 return doubleValue == static_cast<double>(intvalue);
115 }
116
IsZero() const117 bool JSTaggedValue::IsZero() const
118 {
119 if (GetRawData() == VALUE_ZERO) {
120 return true;
121 }
122 if (IsDouble()) {
123 const double limit = 1e-8;
124 return (std::abs(GetDouble() - 0.0) <= limit);
125 }
126 return false;
127 }
128
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)129 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
130 {
131 if (x->IsNumber()) {
132 if (y->IsNumber()) {
133 return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
134 }
135 if (y->IsString()) {
136 JSTaggedNumber yNumber = ToNumber(thread, y);
137 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
138 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
139 }
140 if (y->IsBoolean()) {
141 JSTaggedNumber yNumber = ToNumber(thread, y);
142 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
143 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
144 }
145 if (y->IsBigInt()) {
146 return Equal(thread, y, x);
147 }
148 if (y->IsHeapObject() && !y->IsSymbol()) {
149 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
150 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
151 return Equal(thread, x, yPrimitive);
152 }
153 return false;
154 }
155
156 if (x->IsString()) {
157 if (y->IsString()) {
158 return EcmaStringAccessor::StringsAreEqual(static_cast<EcmaString *>(x->GetTaggedObject()),
159 static_cast<EcmaString *>(y->GetTaggedObject()));
160 }
161 if (y->IsNumber()) {
162 JSTaggedNumber xNumber = ToNumber(thread, x);
163 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
164 return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
165 }
166 if (y->IsBoolean()) {
167 JSTaggedNumber xNumber = ToNumber(thread, x);
168 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
169 JSTaggedNumber yNumber = ToNumber(thread, y);
170 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
171 return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
172 }
173 if (y->IsBigInt()) {
174 return Equal(thread, y, x);
175 }
176 if (y->IsHeapObject() && !y->IsSymbol()) {
177 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
178 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
179 return Equal(thread, x, yPrimitive);
180 }
181 return false;
182 }
183
184 if (x->IsBoolean()) {
185 JSTaggedNumber xNumber = ToNumber(thread, x);
186 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
187 return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
188 }
189
190 if (x->IsSymbol()) {
191 if (y->IsSymbol()) {
192 return x.GetTaggedValue() == y.GetTaggedValue();
193 }
194 if (y->IsBigInt()) {
195 return Equal(thread, y, x);
196 }
197 if (y->IsHeapObject()) {
198 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
199 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
200 return Equal(thread, x, yPrimitive);
201 }
202 return false;
203 }
204
205 if (x->IsBigInt()) {
206 if (y->IsBigInt()) {
207 return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
208 }
209 if (y->IsString()) {
210 JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
211 if (!yNumber->IsBigInt()) {
212 return false;
213 }
214 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
215 }
216 if (y->IsBoolean()) {
217 JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
218 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
219 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
220 }
221 if (y->IsNumber()) {
222 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
223 return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
224 }
225 if (y->IsHeapObject() && !y->IsSymbol()) {
226 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
227 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
228 return Equal(thread, x, yPrimitive);
229 }
230 return false;
231 }
232
233 if (x->IsHeapObject()) {
234 if (y->IsHeapObject()) {
235 // if same type, must call Type::StrictEqual()
236 JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
237 JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
238 if (xType == yType) {
239 return StrictEqual(thread, x, y);
240 }
241 }
242 if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
243 JSHandle<JSTaggedValue> x_primitive(thread, ToPrimitive(thread, x));
244 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
245 return Equal(thread, x_primitive, y);
246 }
247 return false;
248 }
249
250 if (x->IsNull() && y->IsNull()) {
251 return true;
252 }
253
254 if (x->IsUndefined() && y->IsUndefined()) {
255 return true;
256 }
257
258 if (x->IsNull() && y->IsUndefined()) {
259 return true;
260 }
261
262 if (x->IsUndefined() && y->IsNull()) {
263 return true;
264 }
265
266 return false;
267 }
268
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)269 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
270 const JSHandle<JSTaggedValue> &y)
271 {
272 JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
273 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
274 JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
275 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
276 if (primX->IsString() && primY->IsString()) {
277 auto xString = static_cast<EcmaString *>(primX->GetTaggedObject());
278 auto yString = static_cast<EcmaString *>(primY->GetTaggedObject());
279 int result = EcmaStringAccessor::Compare(xString, yString);
280 if (result < 0) {
281 return ComparisonResult::LESS;
282 }
283 if (result == 0) {
284 return ComparisonResult::EQUAL;
285 }
286 return ComparisonResult::GREAT;
287 }
288 if (primX->IsBigInt()) {
289 if (primY->IsNumber()) {
290 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
291 return BigInt::CompareWithNumber(bigint, primY);
292 } else if (primY->IsString()) {
293 JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
294 if (!bigY->IsBigInt()) {
295 return ComparisonResult::UNDEFINED;
296 }
297 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
298 } else {
299 JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
300 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
301 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
302 }
303 }
304 if (primY->IsBigInt()) {
305 ComparisonResult res = Compare(thread, primY, primX);
306 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
307 if (res == ComparisonResult::GREAT) {
308 return ComparisonResult::LESS;
309 } else if (res == ComparisonResult::LESS) {
310 return ComparisonResult::GREAT;
311 }
312 return res;
313 }
314 JSTaggedNumber xNumber = ToNumber(thread, x);
315 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
316 JSTaggedNumber yNumber = ToNumber(thread, y);
317 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
318 return StrictNumberCompare(xNumber.GetNumber(), yNumber.GetNumber());
319 }
320
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)321 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
322 {
323 if (x.IsNumber() && y.IsNumber()) {
324 return true;
325 }
326 if (x.IsBoolean() && y.IsBoolean()) {
327 return true;
328 }
329 if (x.IsString() && y.IsString()) {
330 return true;
331 }
332 if (x.IsHeapObject() && y.IsHeapObject()) {
333 return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
334 }
335
336 return false;
337 }
338
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)339 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
340 PreferredPrimitiveType type)
341 {
342 if (tagged->IsECMAObject()) {
343 EcmaVM *vm = thread->GetEcmaVM();
344 JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
345
346 JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
347 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
348 if (!exoticToprim->IsUndefined()) {
349 JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
350 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
351 EcmaRuntimeCallInfo *info =
352 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
353 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
354 info->SetCallArg(value);
355 JSTaggedValue valueResult = JSFunction::Call(info);
356 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
357 if (!valueResult.IsECMAObject()) {
358 return valueResult;
359 }
360 THROW_TYPE_ERROR_AND_RETURN(thread, "", JSTaggedValue::Exception());
361 } else {
362 type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
363 return OrdinaryToPrimitive(thread, tagged, type);
364 }
365 }
366 return tagged.GetTaggedValue();
367 }
368
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)369 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
370 PreferredPrimitiveType type)
371 {
372 static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
373 ASSERT(tagged->IsECMAObject());
374 auto globalConst = thread->GlobalConstants();
375 for (uint8_t i = 0; i < 2; i++) { // 2: 2 means value has 2 target types, string or value.
376 JSHandle<JSTaggedValue> keyString;
377 if ((static_cast<uint8_t>(type) ^ i) != 0) {
378 keyString = globalConst->GetHandledToStringString();
379 } else {
380 keyString = globalConst->GetHandledValueOfString();
381 }
382 JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
383 if (entryfunc->IsCallable()) {
384 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
385 EcmaRuntimeCallInfo *info =
386 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
387 JSTaggedValue valueResult = JSFunction::Call(info);
388 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
389 if (!valueResult.IsECMAObject()) {
390 return valueResult;
391 }
392 }
393 }
394 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
395 }
396
ToString(JSThread * thread,JSTaggedValue val)397 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
398 {
399 JSHandle<JSTaggedValue> tagged(thread, val);
400 return ToString(thread, tagged);
401 }
402
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)403 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
404 {
405 if (tagged->IsString()) {
406 return JSHandle<EcmaString>(tagged);
407 }
408 auto globalConst = thread->GlobalConstants();
409 if (tagged->IsSpecial()) {
410 switch (tagged->GetRawData()) {
411 case VALUE_UNDEFINED: {
412 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
413 }
414 case VALUE_NULL: {
415 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
416 }
417 case VALUE_TRUE: {
418 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
419 }
420 case VALUE_FALSE: {
421 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
422 }
423 case VALUE_HOLE: {
424 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
425 }
426 default:
427 break;
428 }
429 }
430
431 if (tagged->IsNumber()) {
432 return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
433 }
434
435 if (tagged->IsBigInt()) {
436 JSHandle<BigInt> taggedValue(tagged);
437 return BigInt::ToString(thread, taggedValue);
438 }
439
440 auto emptyStr = globalConst->GetHandledEmptyString();
441 if (tagged->IsECMAObject()) {
442 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
443 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
444 return ToString(thread, primValue);
445 }
446 // Already Include Symbol
447 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
448 }
449
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)450 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
451 {
452 if (tagged->IsNumber()) {
453 return tagged.GetTaggedValue();
454 }
455
456 if (tagged->IsString()) {
457 JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
458 if (EcmaStringAccessor::StringsAreEqual(static_cast<EcmaString *>(tagged->GetTaggedObject()), *str)) {
459 return JSTaggedValue(-0.0);
460 }
461 JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
462 if (SameValue(ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
463 return tmp.GetTaggedValue();
464 }
465 }
466 return JSTaggedValue::Undefined();
467 }
468
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)469 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
470 {
471 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
472 if (tagged->IsInt() || tagged->IsDouble()) {
473 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
474 }
475
476 switch (tagged->GetRawData()) {
477 case JSTaggedValue::VALUE_UNDEFINED: {
478 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
479 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
480 }
481 case JSTaggedValue::VALUE_HOLE: {
482 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
483 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
484 }
485 case JSTaggedValue::VALUE_NULL: {
486 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
487 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
488 }
489 case JSTaggedValue::VALUE_TRUE:
490 case JSTaggedValue::VALUE_FALSE: {
491 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
492 }
493 default: {
494 break;
495 }
496 }
497
498 if (tagged->IsECMAObject()) {
499 return JSHandle<JSObject>::Cast(tagged);
500 }
501 if (tagged->IsSymbol()) {
502 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
503 }
504 if (tagged->IsString()) {
505 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
506 }
507 if (tagged->IsBigInt()) {
508 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
509 }
510 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
511 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
512 }
513
514 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)515 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
516 const JSHandle<JSTaggedValue> &key)
517 {
518 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
519 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
520 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
521 std::string message = "Cannot read property ";
522 message.append(keyStr).append(" of ").append(objStr);
523 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
524 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
525 }
526 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
527
528 if (obj->IsJSProxy()) {
529 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
530 }
531 if (obj->IsTypedArray()) {
532 return JSTypedArray::GetProperty(thread, obj, key);
533 }
534 if (obj->IsModuleNamespace()) {
535 return ModuleNamespace::GetProperty(thread, obj, key);
536 }
537
538 if (obj->IsSpecialContainer()) {
539 return GetJSAPIProperty(thread, obj, key);
540 }
541
542 return JSObject::GetProperty(thread, obj, key);
543 }
544
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)545 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
546 {
547 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
548 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
549 std::string message = "Cannot read property ";
550 message.append(ToCString(key)).append(" of ").append(objStr);
551 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
552 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
553 }
554
555 if (obj->IsJSProxy()) {
556 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
557 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
558 }
559
560 if (obj->IsTypedArray()) {
561 return JSTypedArray::GetProperty(thread, obj, key);
562 }
563
564 if (obj->IsSpecialContainer()) {
565 JSHandle<JSTaggedValue> keyHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue(key));
566 return GetJSAPIProperty(thread, obj, keyHandle);
567 }
568
569 return JSObject::GetProperty(thread, obj, key);
570 }
571
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)572 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
573 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
574 {
575 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
576 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
577 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
578 std::string message = "Cannot read property ";
579 message.append(keyStr).append(" of ").append(objStr);
580 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
581 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
582 }
583 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
584
585 if (obj->IsJSProxy()) {
586 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
587 }
588 if (obj->IsTypedArray()) {
589 return JSTypedArray::GetProperty(thread, obj, key, receiver);
590 }
591
592 if (obj->IsSpecialContainer()) {
593 return GetJSAPIProperty(thread, obj, key);
594 }
595
596 return JSObject::GetProperty(thread, obj, key, receiver);
597 }
598
599 // 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)600 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
601 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow)
602 {
603 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
604 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
605 }
606
607 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
608
609 // 4. Let success be O.[[Set]](P, V, O).
610 bool success = false;
611 if (obj->IsJSProxy()) {
612 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
613 } else if (obj->IsTypedArray()) {
614 success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
615 } else if (obj->IsModuleNamespace()) {
616 success = ModuleNamespace::SetProperty(thread, mayThrow);
617 } else if (obj->IsSpecialContainer()) {
618 success = SetJSAPIProperty(thread, obj, key, value);
619 } else {
620 success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
621 }
622 // 5. ReturnIfAbrupt(success).
623 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
624 // 6. If success is false and Throw is true, throw a TypeError exception.
625 // have done in JSObject::SetPropert.
626 return success;
627 }
628
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)629 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
630 const JSHandle<JSTaggedValue> &value, bool mayThrow)
631 {
632 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
633 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
634 }
635
636 // 4. Let success be O.[[Set]](P, V, O).
637 bool success = false;
638 if (obj->IsJSProxy()) {
639 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
640 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
641 } else if (obj->IsTypedArray()) {
642 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
643 success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
644 } else if (obj->IsModuleNamespace()) {
645 success = ModuleNamespace::SetProperty(thread, mayThrow);
646 } else if (obj->IsSpecialContainer()) {
647 JSHandle<JSTaggedValue> keyHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue(key));
648 success = SetJSAPIProperty(thread, obj, keyHandle, value);
649 } else {
650 success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
651 }
652 // 5. ReturnIfAbrupt(success).
653 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
654 // 6. If success is false and Throw is true, throw a TypeError exception.
655 // have done in JSObject::SetPropert.
656 return success;
657 }
658
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)659 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
660 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
661 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
662 {
663 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
664 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
665 }
666
667 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
668
669 // 4. Let success be O.[[Set]](P, V, O).
670 bool success = false;
671 if (obj->IsJSProxy()) {
672 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
673 } else if (obj->IsTypedArray()) {
674 success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
675 } else if (obj->IsModuleNamespace()) {
676 success = ModuleNamespace::SetProperty(thread, mayThrow);
677 } else if (obj->IsSpecialContainer()) {
678 success = SetJSAPIProperty(thread, obj, key, value);
679 } else {
680 success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
681 }
682 // 5. ReturnIfAbrupt(success).
683 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
684 // 6. If success is false and Throw is true, throw a TypeError exception.
685 // have done in JSObject::SetPropert.
686 return success;
687 }
688
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)689 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
690 const JSHandle<JSTaggedValue> &key)
691 {
692 if (obj->IsJSProxy()) {
693 return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
694 }
695
696 if (obj->IsModuleNamespace()) {
697 return ModuleNamespace::DeleteProperty(thread, obj, key);
698 }
699
700 if (obj->IsTypedArray()) {
701 return JSTypedArray::DeleteProperty(thread, obj, key);
702 }
703
704 if (obj->IsSpecialContainer()) {
705 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
706 }
707
708 return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
709 }
710
711 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)712 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
713 const JSHandle<JSTaggedValue> &key)
714 {
715 if (!obj->IsECMAObject()) {
716 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
717 }
718 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
719
720 // 3. Let success be O.[[Delete]](P).
721 bool success = DeleteProperty(thread, obj, key);
722
723 // 4. ReturnIfAbrupt(success).
724 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
725 // 5. If success is false, throw a TypeError exception
726 if (!success) {
727 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
728 }
729 return success;
730 }
731
732 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)733 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
734 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
735 {
736 // 1. Assert: Type(O) is Object.
737 // 2. Assert: IsPropertyKey(P) is true.
738 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
739 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
740 // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
741 bool success = DefineOwnProperty(thread, obj, key, desc);
742 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
743 // 4. If success is false, throw a TypeError exception.
744 if (!success) {
745 THROW_TYPE_ERROR_AND_RETURN(thread, "", false);
746 }
747 return success;
748 }
749
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)750 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
751 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
752 {
753 if (obj->IsJSArray()) {
754 return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
755 }
756
757 if (obj->IsJSProxy()) {
758 return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
759 }
760
761 if (obj->IsTypedArray()) {
762 return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
763 }
764
765 if (obj->IsModuleNamespace()) {
766 return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
767 }
768
769 if (obj->IsSpecialContainer()) {
770 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
771 }
772
773 return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
774 }
775
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)776 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
777 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
778 {
779 if (obj->IsJSProxy()) {
780 return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
781 }
782 if (obj->IsTypedArray()) {
783 return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
784 }
785 if (obj->IsModuleNamespace()) {
786 return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
787 }
788 if (obj->IsSpecialContainer()) {
789 return GetContainerProperty(thread, obj, key, desc);
790 }
791 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
792 }
793
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto)794 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
795 const JSHandle<JSTaggedValue> &proto)
796 {
797 if (obj->IsJSProxy()) {
798 return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
799 }
800 if (obj->IsModuleNamespace()) {
801 return ModuleNamespace::SetPrototype(obj, proto);
802 }
803 if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
804 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
805 }
806
807 return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto);
808 }
809
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)810 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
811 {
812 if (!obj->IsECMAObject()) {
813 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
814 }
815 if (obj->IsJSProxy()) {
816 return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
817 }
818 return JSObject::GetPrototype(JSHandle<JSObject>(obj));
819 }
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)820 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
821 {
822 if (obj->IsJSProxy()) {
823 return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
824 }
825 if (obj->IsModuleNamespace()) {
826 return ModuleNamespace::PreventExtensions();
827 }
828 return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
829 }
830
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)831 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
832 {
833 if (obj->IsJSProxy()) {
834 return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
835 }
836 if (obj->IsTypedArray()) {
837 return JSTypedArray::OwnPropertyKeys(thread, obj);
838 }
839 if (obj->IsSpecialContainer()) {
840 return GetOwnContainerPropertyKeys(thread, obj);
841 }
842 if (obj->IsModuleNamespace()) {
843 return ModuleNamespace::OwnPropertyKeys(thread, obj);
844 }
845 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
846 }
847
848 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)849 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
850 const JSHandle<JSTaggedValue> &key)
851 {
852 if (obj->IsJSProxy()) {
853 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
854 }
855 if (obj->IsTypedArray()) {
856 return JSTypedArray::HasProperty(thread, obj, key);
857 }
858 if (obj->IsModuleNamespace()) {
859 return ModuleNamespace::HasProperty(thread, obj, key);
860 }
861 if (obj->IsSpecialContainer()) {
862 return HasContainerProperty(thread, obj, key);
863 }
864 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
865 }
866
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)867 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
868 {
869 if (obj->IsJSProxy()) {
870 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
871 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
872 }
873 if (obj->IsTypedArray()) {
874 JSHandle<JSTaggedValue> key_handle(thread, JSTaggedValue(key));
875 return JSTypedArray::HasProperty(thread, obj, key_handle);
876 }
877 if (obj->IsSpecialContainer()) {
878 return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
879 }
880 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
881 }
882
883 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)884 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
885 const JSHandle<JSTaggedValue> &key)
886 {
887 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
888
889 PropertyDescriptor desc(thread);
890 return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
891 }
892
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)893 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
894 {
895 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
896
897 PropertyDescriptor desc(thread);
898 return JSObject::GlobalGetOwnProperty(thread, key, desc);
899 }
900
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)901 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
902 {
903 if (tagged->IsInt() && tagged->GetInt() >= 0) {
904 return JSTaggedNumber(tagged.GetTaggedValue());
905 }
906 if (tagged->IsUndefined()) {
907 return JSTaggedNumber(0);
908 }
909 JSTaggedNumber integerIndex = ToNumber(thread, tagged);
910 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
911 if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
912 return integerIndex;
913 }
914 double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
915 if (len < 0.0 || len > SAFE_NUMBER) {
916 THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
917 JSTaggedNumber::Exception());
918 }
919 return JSTaggedNumber(len);
920 }
921
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)922 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
923 {
924 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
925
926 if (obj->IsNumber()) {
927 return JSHandle<JSTaggedValue>(thread,
928 env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
929 }
930 if (obj->IsBoolean()) {
931 return JSHandle<JSTaggedValue>(thread,
932 env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
933 }
934 if (obj->IsString()) {
935 return JSHandle<JSTaggedValue>(thread,
936 env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
937 }
938 if (obj->IsSymbol()) {
939 return JSHandle<JSTaggedValue>(thread,
940 env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
941 }
942 if (obj->IsBigInt()) {
943 return JSHandle<JSTaggedValue>(thread,
944 env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
945 }
946 return obj;
947 }
948
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)949 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
950 {
951 if (obj->IsUndefined()) {
952 return JSTaggedValue::Undefined();
953 }
954
955 ASSERT(obj->IsECMAObject());
956 return JSTaggedValue::GetPrototype(thread, obj);
957 }
958
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)959 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
960 const JSHandle<JSTaggedValue> &key)
961 {
962 auto *hclass = obj->GetTaggedObject()->GetClass();
963 JSType jsType = hclass->GetObjectType();
964 switch (jsType) {
965 case JSType::JS_API_ARRAY_LIST: {
966 return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
967 }
968 case JSType::JS_API_QUEUE: {
969 return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
970 }
971 case JSType::JS_API_PLAIN_ARRAY: {
972 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
973 }
974 case JSType::JS_API_DEQUE: {
975 return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
976 }
977 case JSType::JS_API_STACK: {
978 return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
979 }
980 case JSType::JS_API_LIST: {
981 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
982 return list->Has(key.GetTaggedValue());
983 }
984 case JSType::JS_API_LINKED_LIST: {
985 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
986 return linkedList->Has(key.GetTaggedValue());
987 }
988 case JSType::JS_API_HASH_MAP:
989 case JSType::JS_API_HASH_SET:
990 case JSType::JS_API_LIGHT_WEIGHT_MAP:
991 case JSType::JS_API_LIGHT_WEIGHT_SET:
992 case JSType::JS_API_TREE_MAP:
993 case JSType::JS_API_TREE_SET: {
994 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
995 }
996 case JSType::JS_API_VECTOR: {
997 return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
998 }
999 default: {
1000 UNREACHABLE();
1001 }
1002 }
1003 return false;
1004 }
1005
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1006 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1007 {
1008 auto *hclass = obj->GetTaggedObject()->GetClass();
1009 JSType jsType = hclass->GetObjectType();
1010 switch (jsType) {
1011 case JSType::JS_API_ARRAY_LIST: {
1012 return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1013 }
1014 case JSType::JS_API_QUEUE: {
1015 return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1016 }
1017 case JSType::JS_API_PLAIN_ARRAY: {
1018 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1019 }
1020 case JSType::JS_API_DEQUE: {
1021 return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1022 }
1023 case JSType::JS_API_STACK: {
1024 return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1025 }
1026 case JSType::JS_API_LIST: {
1027 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1028 }
1029 case JSType::JS_API_LINKED_LIST: {
1030 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1031 }
1032 case JSType::JS_API_HASH_MAP:
1033 case JSType::JS_API_HASH_SET:
1034 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1035 case JSType::JS_API_LIGHT_WEIGHT_SET:
1036 case JSType::JS_API_TREE_MAP:
1037 case JSType::JS_API_TREE_SET: {
1038 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1039 }
1040 case JSType::JS_API_VECTOR: {
1041 return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1042 }
1043 default: {
1044 UNREACHABLE();
1045 }
1046 }
1047 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1048 }
1049
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1050 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1051 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1052 {
1053 if (key->IsInteger()) {
1054 auto *hclass = obj->GetTaggedObject()->GetClass();
1055 JSType jsType = hclass->GetObjectType();
1056 switch (jsType) {
1057 case JSType::JS_API_ARRAY_LIST: {
1058 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1059 }
1060 case JSType::JS_API_QUEUE: {
1061 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1062 }
1063 case JSType::JS_API_DEQUE: {
1064 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1065 }
1066 case JSType::JS_API_STACK: {
1067 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1068 }
1069 case JSType::JS_API_LIST: {
1070 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1071 }
1072 case JSType::JS_API_LINKED_LIST: {
1073 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1074 }
1075 case JSType::JS_API_PLAIN_ARRAY: {
1076 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1077 }
1078 case JSType::JS_API_VECTOR: {
1079 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1080 }
1081 default: {
1082 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1083 }
1084 }
1085 } else {
1086 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1087 }
1088 return false;
1089 }
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1090 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1091 {
1092 // 1. Let primValue be ? ToPrimitive(value, number)
1093 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
1094 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1095 // 2. If Type(primValue) is BigInt, return primValue.
1096 if (primValue->IsBigInt()) {
1097 return primValue;
1098 }
1099 // 3. Return ? ToNumber(primValue).
1100 JSTaggedNumber number = ToNumber(thread, primValue);
1101 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1102 JSHandle<JSTaggedValue> value(thread, number);
1103 return value;
1104 }
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1105 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1106 const JSHandle<JSTaggedValue> &key)
1107 {
1108 if (key->IsInteger()) {
1109 auto *hclass = obj->GetTaggedObject()->GetClass();
1110 JSType jsType = hclass->GetObjectType();
1111 switch (jsType) {
1112 case JSType::JS_API_ARRAY_LIST: {
1113 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1114 }
1115 case JSType::JS_API_LIST: {
1116 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1117 }
1118 case JSType::JS_API_LINKED_LIST: {
1119 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1120 }
1121 case JSType::JS_API_QUEUE: {
1122 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1123 }
1124 case JSType::JS_API_DEQUE: {
1125 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1126 }
1127 case JSType::JS_API_STACK: {
1128 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1129 }
1130 case JSType::JS_API_PLAIN_ARRAY: {
1131 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1132 }
1133 case JSType::JS_API_VECTOR: {
1134 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1135 }
1136 default: {
1137 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1138 }
1139 }
1140 } else {
1141 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1142 }
1143 return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1144 }
1145
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1146 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1147 const JSHandle<JSTaggedValue> &key,
1148 const JSHandle<JSTaggedValue> &value)
1149 {
1150 if (key->IsInteger()) {
1151 auto *hclass = obj->GetTaggedObject()->GetClass();
1152 JSType jsType = hclass->GetObjectType();
1153 switch (jsType) {
1154 case JSType::JS_API_ARRAY_LIST: {
1155 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1156 }
1157 case JSType::JS_API_LIST: {
1158 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1159 }
1160 case JSType::JS_API_LINKED_LIST: {
1161 return JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1162 }
1163 case JSType::JS_API_QUEUE: {
1164 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1165 }
1166 case JSType::JS_API_DEQUE: {
1167 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1168 }
1169 case JSType::JS_API_STACK: {
1170 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1171 }
1172 case JSType::JS_API_PLAIN_ARRAY: {
1173 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1174 }
1175 case JSType::JS_API_VECTOR: {
1176 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1177 }
1178 default: {
1179 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1180 }
1181 }
1182 } else {
1183 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1184 }
1185 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1186 }
1187 } // namespace panda::ecmascript
1188