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 JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass());
818 if (objProtoOrHClass.IsJSHClass() && objFunc->IsDerivedConstructor()) {
819 JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
820 objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype());
821 }
822 }
823
824 return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto);
825 }
826
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)827 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
828 {
829 if (!obj->IsECMAObject()) {
830 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
831 }
832 if (obj->IsJSProxy()) {
833 return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
834 }
835 return JSObject::GetPrototype(JSHandle<JSObject>(obj));
836 }
837
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)838 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
839 {
840 if (obj->IsJSProxy()) {
841 return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
842 }
843 if (obj->IsModuleNamespace()) {
844 return ModuleNamespace::PreventExtensions();
845 }
846 return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
847 }
848
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)849 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
850 {
851 if (obj->IsJSProxy()) {
852 return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
853 }
854 if (obj->IsTypedArray()) {
855 return JSTypedArray::OwnPropertyKeys(thread, obj);
856 }
857 if (obj->IsSpecialContainer()) {
858 return GetOwnContainerPropertyKeys(thread, obj);
859 }
860 if (obj->IsModuleNamespace()) {
861 return ModuleNamespace::OwnPropertyKeys(thread, obj);
862 }
863 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
864 }
865
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)866 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
867 const JSHandle<JSTaggedValue> &obj, uint32_t filter)
868 {
869 if (obj->IsJSProxy()) {
870 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support JSProxy yet";
871 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
872 }
873 if (obj->IsTypedArray()) {
874 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
875 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
876 }
877 if (obj->IsSpecialContainer()) {
878 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
879 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
880 }
881 if (obj->IsModuleNamespace()) {
882 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
883 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
884 }
885 return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
886 }
887
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)888 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
889 {
890 ASSERT(!obj->IsJSProxy());
891 if (obj->IsTypedArray()) {
892 return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
893 }
894 if (obj->IsSpecialContainer()) {
895 return GetOwnContainerEnumPropertyKeys(thread, obj);
896 }
897 if (obj->IsModuleNamespace()) {
898 return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
899 }
900 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
901 }
902
903 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)904 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
905 const JSHandle<JSTaggedValue> &key)
906 {
907 if (obj->IsJSProxy()) {
908 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
909 }
910 if (obj->IsTypedArray()) {
911 return JSTypedArray::HasProperty(thread, obj, key);
912 }
913 if (obj->IsModuleNamespace()) {
914 return ModuleNamespace::HasProperty(thread, obj, key);
915 }
916 if (obj->IsSpecialContainer()) {
917 return HasContainerProperty(thread, obj, key);
918 }
919 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
920 }
921
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)922 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
923 {
924 if (obj->IsJSProxy()) {
925 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
926 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
927 }
928 if (obj->IsTypedArray()) {
929 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
930 return JSTypedArray::HasProperty(thread, obj, keyHandle);
931 }
932 if (obj->IsSpecialContainer()) {
933 return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
934 }
935 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
936 }
937
938 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)939 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
940 const JSHandle<JSTaggedValue> &key)
941 {
942 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
943
944 PropertyDescriptor desc(thread);
945 return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
946 }
947
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)948 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
949 {
950 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
951
952 PropertyDescriptor desc(thread);
953 return JSObject::GlobalGetOwnProperty(thread, key, desc);
954 }
955
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)956 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
957 {
958 // 1. If v is an Object, return true.
959 if (tagged->IsECMAObject()) {
960 return true;
961 }
962 // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
963 if (tagged->IsSymbol()) {
964 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
965 auto *table = env->GetRegisterSymbols().GetObject<SymbolTable>();
966 JSTaggedValue key = table->FindSymbol(tagged.GetTaggedValue());
967 if (key.IsUndefined()) {
968 return true;
969 }
970 }
971 // 3. Return false.
972 return false;
973 }
974
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)975 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
976 {
977 if (tagged->IsInt() && tagged->GetInt() >= 0) {
978 return JSTaggedNumber(tagged.GetTaggedValue());
979 }
980 if (tagged->IsUndefined()) {
981 return JSTaggedNumber(0);
982 }
983 JSTaggedNumber integerIndex = ToNumber(thread, tagged);
984 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
985 if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
986 return integerIndex;
987 }
988 double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
989 if (len < 0.0 || len > SAFE_NUMBER) {
990 THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
991 JSTaggedNumber::Exception());
992 }
993 return JSTaggedNumber(len);
994 }
995
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)996 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
997 {
998 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
999
1000 if (obj->IsNumber()) {
1001 return JSHandle<JSTaggedValue>(thread,
1002 env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1003 }
1004 if (obj->IsBoolean()) {
1005 return JSHandle<JSTaggedValue>(thread,
1006 env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1007 }
1008 if (obj->IsString()) {
1009 return JSHandle<JSTaggedValue>(thread,
1010 env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1011 }
1012 if (obj->IsSymbol()) {
1013 return JSHandle<JSTaggedValue>(thread,
1014 env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1015 }
1016 if (obj->IsBigInt()) {
1017 return JSHandle<JSTaggedValue>(thread,
1018 env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1019 }
1020 return obj;
1021 }
1022
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1023 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1024 {
1025 if (obj->IsUndefined()) {
1026 return JSTaggedValue::Undefined();
1027 }
1028
1029 ASSERT(obj->IsECMAObject());
1030 return JSTaggedValue::GetPrototype(thread, obj);
1031 }
1032
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1033 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1034 const JSHandle<JSTaggedValue> &key)
1035 {
1036 auto *hclass = obj->GetTaggedObject()->GetClass();
1037 JSType jsType = hclass->GetObjectType();
1038 switch (jsType) {
1039 case JSType::JS_API_ARRAY_LIST: {
1040 return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
1041 }
1042 case JSType::JS_API_QUEUE: {
1043 return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
1044 }
1045 case JSType::JS_API_PLAIN_ARRAY: {
1046 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1047 }
1048 case JSType::JS_API_DEQUE: {
1049 return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
1050 }
1051 case JSType::JS_API_STACK: {
1052 return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
1053 }
1054 case JSType::JS_API_LIST: {
1055 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1056 return list->Has(key.GetTaggedValue());
1057 }
1058 case JSType::JS_API_LINKED_LIST: {
1059 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1060 return linkedList->Has(key.GetTaggedValue());
1061 }
1062 case JSType::JS_API_HASH_MAP:
1063 case JSType::JS_API_HASH_SET:
1064 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1065 case JSType::JS_API_LIGHT_WEIGHT_SET:
1066 case JSType::JS_API_TREE_MAP:
1067 case JSType::JS_API_TREE_SET: {
1068 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1069 }
1070 case JSType::JS_API_VECTOR: {
1071 return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
1072 }
1073 default: {
1074 LOG_ECMA(FATAL) << "this branch is unreachable";
1075 UNREACHABLE();
1076 }
1077 }
1078 return false;
1079 }
1080
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1081 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1082 {
1083 auto *hclass = obj->GetTaggedObject()->GetClass();
1084 JSType jsType = hclass->GetObjectType();
1085 switch (jsType) {
1086 case JSType::JS_API_ARRAY_LIST: {
1087 return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1088 }
1089 case JSType::JS_API_QUEUE: {
1090 return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1091 }
1092 case JSType::JS_API_PLAIN_ARRAY: {
1093 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1094 }
1095 case JSType::JS_API_DEQUE: {
1096 return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1097 }
1098 case JSType::JS_API_STACK: {
1099 return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1100 }
1101 case JSType::JS_API_LIST: {
1102 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1103 }
1104 case JSType::JS_API_LINKED_LIST: {
1105 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1106 }
1107 case JSType::JS_API_HASH_MAP:
1108 case JSType::JS_API_HASH_SET:
1109 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1110 case JSType::JS_API_LIGHT_WEIGHT_SET:
1111 case JSType::JS_API_TREE_MAP:
1112 case JSType::JS_API_TREE_SET: {
1113 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1114 }
1115 case JSType::JS_API_VECTOR: {
1116 return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1117 }
1118 default: {
1119 LOG_ECMA(FATAL) << "this branch is unreachable";
1120 UNREACHABLE();
1121 }
1122 }
1123 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1124 }
1125
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1126 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1127 const JSHandle<JSTaggedValue> &obj)
1128 {
1129 auto *hclass = obj->GetTaggedObject()->GetClass();
1130 JSType jsType = hclass->GetObjectType();
1131 switch (jsType) {
1132 case JSType::JS_API_QUEUE: {
1133 return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1134 }
1135 case JSType::JS_API_DEQUE: {
1136 return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1137 }
1138 case JSType::JS_API_LIST: {
1139 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1140 }
1141 case JSType::JS_API_LINKED_LIST: {
1142 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1143 }
1144 case JSType::JS_API_VECTOR:
1145 case JSType::JS_API_STACK:
1146 case JSType::JS_API_ARRAY_LIST:
1147 case JSType::JS_API_PLAIN_ARRAY:
1148 case JSType::JS_API_HASH_MAP:
1149 case JSType::JS_API_HASH_SET:
1150 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1151 case JSType::JS_API_LIGHT_WEIGHT_SET:
1152 case JSType::JS_API_TREE_MAP:
1153 case JSType::JS_API_TREE_SET: {
1154 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1155 }
1156 default: {
1157 UNREACHABLE();
1158 }
1159 }
1160 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1161 }
1162
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1163 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1164 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1165 {
1166 if (key->IsInteger()) {
1167 auto *hclass = obj->GetTaggedObject()->GetClass();
1168 JSType jsType = hclass->GetObjectType();
1169 switch (jsType) {
1170 case JSType::JS_API_ARRAY_LIST: {
1171 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1172 }
1173 case JSType::JS_API_QUEUE: {
1174 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1175 }
1176 case JSType::JS_API_DEQUE: {
1177 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1178 }
1179 case JSType::JS_API_STACK: {
1180 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1181 }
1182 case JSType::JS_API_LIST: {
1183 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1184 }
1185 case JSType::JS_API_LINKED_LIST: {
1186 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1187 }
1188 case JSType::JS_API_PLAIN_ARRAY: {
1189 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1190 }
1191 case JSType::JS_API_VECTOR: {
1192 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1193 }
1194 default: {
1195 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1196 }
1197 }
1198 } else {
1199 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1200 }
1201 return false;
1202 }
1203
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1204 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1205 {
1206 // 1. Let primValue be ? ToPrimitive(value, number)
1207 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
1208 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1209 // 2. If Type(primValue) is BigInt, return primValue.
1210 if (primValue->IsBigInt()) {
1211 return primValue;
1212 }
1213 // 3. Return ? ToNumber(primValue).
1214 JSTaggedNumber number = ToNumber(thread, primValue);
1215 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1216 JSHandle<JSTaggedValue> value(thread, number);
1217 return value;
1218 }
1219
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1220 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1221 const JSHandle<JSTaggedValue> &key)
1222 {
1223 if (key->IsInteger()) {
1224 auto *hclass = obj->GetTaggedObject()->GetClass();
1225 JSType jsType = hclass->GetObjectType();
1226 switch (jsType) {
1227 case JSType::JS_API_ARRAY_LIST: {
1228 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1229 }
1230 case JSType::JS_API_LIST: {
1231 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1232 }
1233 case JSType::JS_API_LINKED_LIST: {
1234 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1235 }
1236 case JSType::JS_API_QUEUE: {
1237 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1238 }
1239 case JSType::JS_API_DEQUE: {
1240 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1241 }
1242 case JSType::JS_API_STACK: {
1243 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1244 }
1245 case JSType::JS_API_PLAIN_ARRAY: {
1246 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1247 }
1248 case JSType::JS_API_VECTOR: {
1249 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1250 }
1251 default: {
1252 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1253 }
1254 }
1255 } else {
1256 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1257 }
1258 return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1259 }
1260
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1261 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1262 const JSHandle<JSTaggedValue> &key,
1263 const JSHandle<JSTaggedValue> &value)
1264 {
1265 if (key->IsInteger()) {
1266 auto *hclass = obj->GetTaggedObject()->GetClass();
1267 JSType jsType = hclass->GetObjectType();
1268 switch (jsType) {
1269 case JSType::JS_API_ARRAY_LIST: {
1270 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1271 }
1272 case JSType::JS_API_LIST: {
1273 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1274 }
1275 case JSType::JS_API_LINKED_LIST: {
1276 return JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1277 }
1278 case JSType::JS_API_QUEUE: {
1279 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1280 }
1281 case JSType::JS_API_DEQUE: {
1282 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1283 }
1284 case JSType::JS_API_STACK: {
1285 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1286 }
1287 case JSType::JS_API_PLAIN_ARRAY: {
1288 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1289 }
1290 case JSType::JS_API_VECTOR: {
1291 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1292 }
1293 default: {
1294 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1295 }
1296 }
1297 } else {
1298 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1299 }
1300 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1301 }
1302 } // namespace panda::ecmascript
1303