• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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