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