1
2 /**
3 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "plugins/ets/runtime/ets_class_linker_extension.h"
18 #include "plugins/ets/runtime/ets_stubs-inl.h"
19 #include "plugins/ets/runtime/types/ets_box_primitive.h"
20 #include "plugins/ets/runtime/types/ets_bigint.h"
21
22 namespace ark::ets {
23
24 template <typename T>
GetBoxedNumericValue(EtsClassLinkerExtension * ext,EtsObject * obj)25 static std::optional<T> GetBoxedNumericValue(EtsClassLinkerExtension *ext, EtsObject *obj)
26 {
27 auto *cls = obj->GetClass()->GetRuntimeClass();
28
29 auto const getValue = [obj](auto typeId) {
30 using Type = typename decltype(typeId)::type;
31 return static_cast<T>(EtsBoxPrimitive<Type>::FromCoreType(obj)->GetValue());
32 };
33
34 if (cls == ext->GetBoxDoubleClass()) {
35 return getValue(helpers::TypeIdentity<EtsDouble>());
36 }
37 if (cls == ext->GetBoxIntClass()) {
38 return getValue(helpers::TypeIdentity<EtsInt>());
39 }
40
41 if (cls == ext->GetBoxByteClass()) {
42 return getValue(helpers::TypeIdentity<EtsByte>());
43 }
44 if (cls == ext->GetBoxShortClass()) {
45 return getValue(helpers::TypeIdentity<EtsShort>());
46 }
47 if (cls == ext->GetBoxLongClass()) {
48 return getValue(helpers::TypeIdentity<EtsLong>());
49 }
50 if (cls == ext->GetBoxFloatClass()) {
51 return getValue(helpers::TypeIdentity<EtsFloat>());
52 }
53 return std::nullopt;
54 }
55
EtsBigIntEquality(EtsBigInt * obj1,EtsBigInt * obj2)56 static bool EtsBigIntEquality(EtsBigInt *obj1, EtsBigInt *obj2)
57 {
58 auto bytes1 = obj1->GetBytes();
59 auto bytes2 = obj2->GetBytes();
60 ASSERT(bytes1 != nullptr && bytes2 != nullptr);
61
62 auto size1 = bytes1->GetActualLength();
63 auto size2 = bytes2->GetActualLength();
64 ASSERT(size1 != 0 && size2 != 0);
65 auto data1 = bytes1->GetData();
66 auto data2 = bytes2->GetData();
67 ASSERT(data1 != nullptr && data2 != nullptr);
68 ASSERT(data1->GetLength() >= size1 && data2->GetLength() >= size2);
69
70 auto const readElem = [](auto *arr, uint32_t i) { return arr->Get(i)->GetValue(); };
71
72 if (size1 != size2) {
73 return false;
74 }
75
76 // start with check of MSD, which is sign.
77 for (int i = size1 - 1; i >= 0; --i) {
78 if (readElem(data1, i) != readElem(data2, i)) {
79 return false;
80 }
81 }
82 return true;
83 }
84
85 template <typename BoxedType>
CompareBoxedPrimitive(EtsObject * obj1,EtsObject * obj2)86 static bool CompareBoxedPrimitive(EtsObject *obj1, EtsObject *obj2)
87 {
88 return EtsBoxPrimitive<BoxedType>::FromCoreType(obj1)->GetValue() ==
89 EtsBoxPrimitive<BoxedType>::FromCoreType(obj2)->GetValue();
90 }
91
EtsValueTypedEquals(EtsCoroutine * coro,EtsObject * obj1,EtsObject * obj2)92 bool EtsValueTypedEquals(EtsCoroutine *coro, EtsObject *obj1, EtsObject *obj2)
93 {
94 auto ecls1 = obj1->GetClass();
95 auto ecls2 = obj2->GetClass();
96 auto cls1 = ecls1->GetRuntimeClass();
97 auto cls2 = ecls2->GetRuntimeClass();
98 ASSERT(ecls1->IsValueTyped() && ecls1->IsValueTyped());
99
100 auto ext = coro->GetPandaVM()->GetClassLinker()->GetEtsClassLinkerExtension();
101
102 if (cls1->IsStringClass()) {
103 return cls2->IsStringClass() &&
104 coretypes::String::Cast(obj1->GetCoreType())->Compare(coretypes::String::Cast(obj2->GetCoreType())) == 0;
105 }
106 if (cls1 == ext->GetBoxBooleanClass()) {
107 return cls2 == ext->GetBoxBooleanClass() && CompareBoxedPrimitive<EtsBoolean>(obj1, obj2);
108 }
109 if (cls1 == ext->GetBoxCharClass()) {
110 return cls2 == ext->GetBoxCharClass() && CompareBoxedPrimitive<EtsChar>(obj1, obj2);
111 }
112 if (UNLIKELY(cls1 == ext->GetBigIntClass())) {
113 return cls2 == ext->GetBigIntClass() &&
114 EtsBigIntEquality(EtsBigInt::FromEtsObject(obj1), EtsBigInt::FromEtsObject(obj2));
115 }
116 if (cls1 == ext->GetBoxLongClass() && cls2 == ext->GetBoxLongClass()) {
117 return CompareBoxedPrimitive<EtsLong>(obj1, obj2);
118 }
119 if (auto num1 = GetBoxedNumericValue<EtsDouble>(ext, obj1); num1.has_value()) {
120 auto num2 = GetBoxedNumericValue<EtsDouble>(ext, obj2);
121 return num2.has_value() && num2.value() == num1.value();
122 }
123 UNREACHABLE();
124 }
125
126 } // namespace ark::ets
127