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 #include "plugins/ets/runtime/types/ets_string.h"
22
23 namespace ark::ets {
24
25 template <typename T>
GetBoxedNumericValue(EtsClassLinkerExtension * ext,EtsObject * obj)26 static std::optional<T> GetBoxedNumericValue(EtsClassLinkerExtension *ext, EtsObject *obj)
27 {
28 auto *cls = obj->GetClass()->GetRuntimeClass();
29
30 auto const getValue = [obj](auto typeId) {
31 using Type = typename decltype(typeId)::type;
32 return static_cast<T>(EtsBoxPrimitive<Type>::FromCoreType(obj)->GetValue());
33 };
34
35 if (cls == ext->GetBoxDoubleClass()) {
36 return getValue(helpers::TypeIdentity<EtsDouble>());
37 }
38 if (cls == ext->GetBoxIntClass()) {
39 return getValue(helpers::TypeIdentity<EtsInt>());
40 }
41
42 if (cls == ext->GetBoxByteClass()) {
43 return getValue(helpers::TypeIdentity<EtsByte>());
44 }
45 if (cls == ext->GetBoxShortClass()) {
46 return getValue(helpers::TypeIdentity<EtsShort>());
47 }
48 if (cls == ext->GetBoxLongClass()) {
49 return getValue(helpers::TypeIdentity<EtsLong>());
50 }
51 if (cls == ext->GetBoxFloatClass()) {
52 return getValue(helpers::TypeIdentity<EtsFloat>());
53 }
54 return std::nullopt;
55 }
56
EtsBigIntEquality(EtsBigInt * obj1,EtsBigInt * obj2)57 static bool EtsBigIntEquality(EtsBigInt *obj1, EtsBigInt *obj2)
58 {
59 auto bytes1 = obj1->GetBytes();
60 auto bytes2 = obj2->GetBytes();
61 ASSERT(bytes1 != nullptr && bytes2 != nullptr);
62
63 auto size1 = bytes1->GetActualLength();
64 auto size2 = bytes2->GetActualLength();
65 ASSERT(size1 != 0 && size2 != 0);
66 auto data1 = bytes1->GetData();
67 auto data2 = bytes2->GetData();
68 ASSERT(data1 != nullptr && data2 != nullptr);
69 ASSERT(data1->GetLength() >= size1 && data2->GetLength() >= size2);
70
71 auto const readElem = [](auto *arr, uint32_t i) { return arr->Get(i)->GetValue(); };
72
73 if (size1 != size2) {
74 return false;
75 }
76
77 // start with check of MSD, which is sign.
78 for (int i = size1 - 1; i >= 0; --i) {
79 if (readElem(data1, i) != readElem(data2, i)) {
80 return false;
81 }
82 }
83 return true;
84 }
85
86 template <typename BoxedType>
CompareBoxedPrimitive(EtsObject * obj1,EtsObject * obj2)87 static bool CompareBoxedPrimitive(EtsObject *obj1, EtsObject *obj2)
88 {
89 return EtsBoxPrimitive<BoxedType>::FromCoreType(obj1)->GetValue() ==
90 EtsBoxPrimitive<BoxedType>::FromCoreType(obj2)->GetValue();
91 }
92
EtsValueTypedEquals(EtsCoroutine * coro,EtsObject * obj1,EtsObject * obj2)93 bool EtsValueTypedEquals(EtsCoroutine *coro, EtsObject *obj1, EtsObject *obj2)
94 {
95 auto ecls1 = obj1->GetClass();
96 auto ecls2 = obj2->GetClass();
97 auto cls1 = ecls1->GetRuntimeClass();
98 auto cls2 = ecls2->GetRuntimeClass();
99 ASSERT(ecls1->IsValueTyped() && ecls1->IsValueTyped());
100
101 auto ext = coro->GetPandaVM()->GetClassLinker()->GetEtsClassLinkerExtension();
102
103 if (cls1->IsStringClass()) {
104 return cls2->IsStringClass() &&
105 coretypes::String::Cast(obj1->GetCoreType())->Compare(coretypes::String::Cast(obj2->GetCoreType())) == 0;
106 }
107 if (cls1 == ext->GetBoxBooleanClass()) {
108 return cls2 == ext->GetBoxBooleanClass() && CompareBoxedPrimitive<EtsBoolean>(obj1, obj2);
109 }
110 if (cls1 == ext->GetBoxCharClass()) {
111 return cls2 == ext->GetBoxCharClass() && CompareBoxedPrimitive<EtsChar>(obj1, obj2);
112 }
113 if (UNLIKELY(ecls1->IsBigInt())) {
114 return ecls2->IsBigInt() && 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
EtsGetTypeof(EtsCoroutine * coro,EtsObject * obj)126 EtsString *EtsGetTypeof(EtsCoroutine *coro, EtsObject *obj)
127 {
128 // NOTE(vpukhov): #19799 use string constants
129 auto ext = coro->GetPandaVM()->GetClassLinker()->GetEtsClassLinkerExtension();
130 if (obj == nullptr) {
131 return EtsString::CreateFromMUtf8("object");
132 }
133 EtsClass *cls = obj->GetClass();
134
135 // NOTE(vpukhov): re-encode subtyping flags if necessary
136 if (!cls->IsValueTyped()) {
137 if (cls->IsFunction()) {
138 return EtsString::CreateFromMUtf8("function");
139 }
140 return EtsString::CreateFromMUtf8("object");
141 }
142
143 if (cls->IsUndefined()) {
144 return EtsString::CreateFromMUtf8("undefined");
145 }
146 if (obj->IsStringClass()) {
147 return EtsString::CreateFromMUtf8("string");
148 }
149 if (cls->IsBigInt()) {
150 return EtsString::CreateFromMUtf8("bigint");
151 }
152
153 ASSERT(cls->IsBoxed());
154
155 auto rcls = cls->GetRuntimeClass();
156 if (rcls == ext->GetBoxBooleanClass()) {
157 return EtsString::CreateFromMUtf8("boolean");
158 }
159 // NOTE(vpukhov): #19653 numerics must map to "number"
160 if (rcls == ext->GetBoxByteClass()) {
161 return EtsString::CreateFromMUtf8("byte");
162 }
163 if (rcls == ext->GetBoxCharClass()) {
164 return EtsString::CreateFromMUtf8("char");
165 }
166 if (rcls == ext->GetBoxShortClass()) {
167 return EtsString::CreateFromMUtf8("short");
168 }
169 if (rcls == ext->GetBoxIntClass()) {
170 return EtsString::CreateFromMUtf8("int");
171 }
172 if (rcls == ext->GetBoxLongClass()) {
173 return EtsString::CreateFromMUtf8("long");
174 }
175 if (rcls == ext->GetBoxFloatClass()) {
176 return EtsString::CreateFromMUtf8("float");
177 }
178 if (rcls == ext->GetBoxDoubleClass()) {
179 return EtsString::CreateFromMUtf8("number");
180 }
181 UNREACHABLE();
182 }
183
184 } // namespace ark::ets
185