• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "intrinsics.h"
17 
18 #include "plugins/ets/runtime/ets_exceptions.h"
19 #include "runtime/include/exceptions.h"
20 #include "compiler/optimizer/ir/constants.h"
21 
22 #include "plugins/ets/runtime/ets_class_linker_extension.h"
23 #include "plugins/ets/runtime/ets_stubs-inl.h"
24 #include "plugins/ets/runtime/intrinsics/helpers/ets_to_string_cache.h"
25 namespace ark::ets::intrinsics {
26 
27 template <panda_file::Type::TypeId FIELD_TYPE, bool IS_GETTER>
TryGetField(ark::Method * method,Field * rawField,uint32_t pc,ark::Class * klass)28 Field *TryGetField(ark::Method *method, Field *rawField, uint32_t pc, ark::Class *klass)
29 {
30     bool useIc = pc != ark::compiler::INVALID_PC;
31     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
32     auto address = method->GetInstructions() + (useIc ? pc : 0);
33     ASSERT(EtsCoroutine::GetCurrent() != nullptr);
34     InterpreterCache *cache = EtsCoroutine::GetCurrent()->GetInterpreterCache();
35     return GetFieldByName<IS_GETTER>(cache->GetEntry(address), method, rawField, address, klass);
36 }
37 
38 template <panda_file::Type::TypeId FIELD_TYPE, bool IS_GETTER>
TryGetCallee(ark::Method * method,Field * rawField,uint32_t pc,ark::Class * klass)39 ark::Method *TryGetCallee(ark::Method *method, Field *rawField, uint32_t pc, ark::Class *klass)
40 {
41     bool useIc = pc != ark::compiler::INVALID_PC;
42     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
43     auto address = method->GetInstructions() + (useIc ? pc : 0);
44     ASSERT(EtsCoroutine::GetCurrent() != nullptr);
45     InterpreterCache *cache = EtsCoroutine::GetCurrent()->GetInterpreterCache();
46     return GetAccessorByName<FIELD_TYPE, IS_GETTER>(cache->GetEntry(address), method, rawField, address, klass);
47 }
48 
49 template <panda_file::Type::TypeId FIELD_TYPE, class T>
GetFieldPrimitiveType(Field * field,const VMHandle<ObjectHeader> & handleObj)50 static T GetFieldPrimitiveType(Field *field, const VMHandle<ObjectHeader> &handleObj)
51 {
52     ASSERT(handleObj.GetPtr() != nullptr);
53     switch (field->GetTypeId()) {
54         case panda_file::Type::TypeId::U1:
55         case panda_file::Type::TypeId::U8: {
56             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
57             return handleObj.GetPtr()->template GetFieldPrimitive<uint8_t>(*field);
58         }
59         case panda_file::Type::TypeId::I8: {
60             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
61             return handleObj.GetPtr()->template GetFieldPrimitive<int8_t>(*field);
62         }
63         case panda_file::Type::TypeId::I16: {
64             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
65             return handleObj.GetPtr()->template GetFieldPrimitive<int16_t>(*field);
66         }
67         case panda_file::Type::TypeId::U16: {
68             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
69             return handleObj.GetPtr()->template GetFieldPrimitive<uint16_t>(*field);
70         }
71         case panda_file::Type::TypeId::I32: {
72             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
73             return handleObj.GetPtr()->template GetFieldPrimitive<int32_t>(*field);
74         }
75         case panda_file::Type::TypeId::U32: {
76             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
77             return handleObj.GetPtr()->template GetFieldPrimitive<uint32_t>(*field);
78         }
79         case panda_file::Type::TypeId::I64: {
80             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I64);
81             return handleObj.GetPtr()->template GetFieldPrimitive<int64_t>(*field);
82         }
83         case panda_file::Type::TypeId::U64: {
84             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I64);
85             return handleObj.GetPtr()->template GetFieldPrimitive<uint64_t>(*field);
86         }
87         case panda_file::Type::TypeId::F32: {
88             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::F32);
89             return handleObj.GetPtr()->template GetFieldPrimitive<float>(*field);
90         }
91         case panda_file::Type::TypeId::F64: {
92             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::F64);
93             return handleObj.GetPtr()->template GetFieldPrimitive<double>(*field);
94         }
95         default:
96             UNREACHABLE();
97             return handleObj.GetPtr()->template GetFieldPrimitive<T>(*field);
98     }
99 }
100 
101 template <panda_file::Type::TypeId FIELD_TYPE, class T>
CompilerEtsLdObjByName(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)102 T CompilerEtsLdObjByName(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
103 {
104     ASSERT(method != nullptr);
105     ark::Class *klass;
106     ark::Field *rawField;
107     {
108         auto *thread = ManagedThread::GetCurrent();
109         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
110         VMHandle<ObjectHeader> handleObj(thread, obj);
111         auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
112         ASSERT(handleObj.GetPtr() != nullptr);
113         klass = static_cast<ark::Class *>(handleObj.GetPtr()->ClassAddr<ark::BaseClass>());
114         rawField = classLinker->GetField(*method, panda_file::File::EntityId(id), false);
115 
116         Field *field = TryGetField<FIELD_TYPE, true>(method, rawField, pc, klass);
117         if (field != nullptr) {
118             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
119                 return handleObj.GetPtr()->GetFieldObject(*field);
120             } else {
121                 return GetFieldPrimitiveType<FIELD_TYPE, T>(field, handleObj);
122             }
123         }
124 
125         auto callee = TryGetCallee<FIELD_TYPE, true>(method, rawField, pc, klass);
126         if (callee != nullptr) {
127             Value val(handleObj.GetPtr());
128             Value result = callee->Invoke(Coroutine::GetCurrent(), &val);
129             return result.GetAs<T>();
130         }
131     }
132     LookUpException<true>(klass, rawField);
133     HandlePendingException();
134     UNREACHABLE();
135 }
136 
137 template <panda_file::Type::TypeId FIELD_TYPE, class T>
138 /* CC-OFFNXT(G.FUN.01-CPP, huge_method) big switch-case */
SetTypedFieldPrimitive(Field * field,const VMHandle<ObjectHeader> & handleObj,T storeValue)139 static void SetTypedFieldPrimitive(Field *field, const VMHandle<ObjectHeader> &handleObj, T storeValue)
140 {
141     ASSERT(handleObj.GetPtr() != nullptr);
142     switch (field->GetTypeId()) {
143         case panda_file::Type::TypeId::U1:
144         case panda_file::Type::TypeId::U8: {
145             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
146             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint8_t>(storeValue));
147             return;
148         }
149         case panda_file::Type::TypeId::I8: {
150             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
151             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int8_t>(storeValue));
152             return;
153         }
154         case panda_file::Type::TypeId::I16: {
155             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
156             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int16_t>(storeValue));
157             return;
158         }
159         case panda_file::Type::TypeId::U16: {
160             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
161             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint16_t>(storeValue));
162             return;
163         }
164         case panda_file::Type::TypeId::I32: {
165             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
166             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int32_t>(storeValue));
167             return;
168         }
169         case panda_file::Type::TypeId::U32: {
170             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
171             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint32_t>(storeValue));
172             return;
173         }
174         case panda_file::Type::TypeId::I64: {
175             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I64);
176             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int64_t>(storeValue));
177             return;
178         }
179         case panda_file::Type::TypeId::U64: {
180             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I64);
181             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint64_t>(storeValue));
182             return;
183         }
184         case panda_file::Type::TypeId::F32: {
185             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::F32);
186             handleObj.GetPtr()->SetFieldPrimitive(*field, storeValue);
187             return;
188         }
189         case panda_file::Type::TypeId::F64: {
190             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::F64);
191             handleObj.GetPtr()->SetFieldPrimitive(*field, storeValue);
192             return;
193         }
194         default: {
195             UNREACHABLE();
196         }
197     }
198 }
199 
200 template <panda_file::Type::TypeId FIELD_TYPE, class T>
CompilerEtsStObjByName(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,T storeValue)201 void CompilerEtsStObjByName(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj, T storeValue)
202 {
203     ASSERT(method != nullptr);
204     ark::Class *klass;
205     ark::Field *rawField;
206     {
207         auto *thread = ManagedThread::GetCurrent();
208         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
209         VMHandle<ObjectHeader> handleObj(thread, obj);
210         auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
211         klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
212         rawField = classLinker->GetField(*method, panda_file::File::EntityId(id), false);
213 
214         Field *field = TryGetField<FIELD_TYPE, false>(method, rawField, pc, klass);
215         if (field != nullptr) {
216             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
217                 UNREACHABLE();
218             } else {
219                 SetTypedFieldPrimitive<FIELD_TYPE, T>(field, handleObj, storeValue);
220                 return;
221             }
222         }
223 
224         auto callee = TryGetCallee<FIELD_TYPE, false>(method, rawField, pc, klass);
225         if (callee != nullptr) {
226             PandaVector<Value> args {Value(handleObj.GetPtr()), Value(storeValue)};
227             callee->Invoke(Coroutine::GetCurrent(), args.data());
228             return;
229         }
230     }
231     LookUpException<false>(klass, rawField);
232     HandlePendingException();
233     UNREACHABLE();
234 }
235 
CompilerEtsStObjByNameRef(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,ark::ObjectHeader * storeValue)236 void CompilerEtsStObjByNameRef(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
237                                ark::ObjectHeader *storeValue)
238 {
239     ASSERT(method != nullptr);
240     ark::Class *klass;
241     ark::Field *rawField;
242     {
243         auto *thread = ManagedThread::GetCurrent();
244         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
245         VMHandle<ObjectHeader> handleObj(thread, obj);
246         VMHandle<ObjectHeader> handleStore(thread, storeValue);
247         auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
248         klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
249         rawField = classLinker->GetField(*method, panda_file::File::EntityId(id), false);
250 
251         Field *field = TryGetField<panda_file::Type::TypeId::REFERENCE, false>(method, rawField, pc, klass);
252         if (field != nullptr) {
253             ASSERT(handleObj.GetPtr() != nullptr);
254             return handleObj.GetPtr()->SetFieldObject(*field, handleStore.GetPtr());
255         }
256 
257         auto callee = TryGetCallee<panda_file::Type::TypeId::REFERENCE, false>(method, rawField, pc, klass);
258         if (callee != nullptr) {
259             PandaVector<Value> args {Value(handleObj.GetPtr()), Value(handleStore.GetPtr())};
260             callee->Invoke(Coroutine::GetCurrent(), args.data());
261             return;
262         }
263     }
264     LookUpException<false>(klass, rawField);
265     HandlePendingException();
266     UNREACHABLE();
267 }
268 
CompilerEtsLdObjByNameI32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)269 extern "C" int32_t CompilerEtsLdObjByNameI32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
270 {
271     return CompilerEtsLdObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj);
272 }
273 
CompilerEtsLdObjByNameI64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)274 extern "C" int64_t CompilerEtsLdObjByNameI64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
275 {
276     return CompilerEtsLdObjByName<panda_file::Type::TypeId::I64, int64_t>(method, id, pc, obj);
277 }
278 
CompilerEtsLdObjByNameF32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)279 extern "C" float CompilerEtsLdObjByNameF32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
280 {
281     return CompilerEtsLdObjByName<panda_file::Type::TypeId::F32, float>(method, id, pc, obj);
282 }
283 
CompilerEtsLdObjByNameF64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)284 extern "C" double CompilerEtsLdObjByNameF64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
285 {
286     return CompilerEtsLdObjByName<panda_file::Type::TypeId::F64, double>(method, id, pc, obj);
287 }
288 
CompilerEtsLdObjByNameObj(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)289 extern "C" ark::ObjectHeader *CompilerEtsLdObjByNameObj(ark::Method *method, int32_t id, uint32_t pc,
290                                                         ark::ObjectHeader *obj)
291 {
292     return CompilerEtsLdObjByName<panda_file::Type::TypeId::REFERENCE, ark::ObjectHeader *>(method, id, pc, obj);
293 }
294 
CompilerEtsStObjByNameI8(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int8_t storeValue)295 extern "C" void CompilerEtsStObjByNameI8(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
296                                          int8_t storeValue)
297 {
298     CompilerEtsStObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj,
299                                                                    static_cast<int32_t>(storeValue));
300 }
301 
CompilerEtsStObjByNameI16(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int16_t storeValue)302 extern "C" void CompilerEtsStObjByNameI16(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
303                                           int16_t storeValue)
304 {
305     CompilerEtsStObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj,
306                                                                    static_cast<int32_t>(storeValue));
307 }
308 
CompilerEtsStObjByNameI32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int32_t storeValue)309 extern "C" void CompilerEtsStObjByNameI32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
310                                           int32_t storeValue)
311 {
312     CompilerEtsStObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj, storeValue);
313 }
314 
CompilerEtsStObjByNameI64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int64_t storeValue)315 extern "C" void CompilerEtsStObjByNameI64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
316                                           int64_t storeValue)
317 {
318     CompilerEtsStObjByName<panda_file::Type::TypeId::I64, int64_t>(method, id, pc, obj, storeValue);
319 }
320 
CompilerEtsStObjByNameF32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,float storeValue)321 extern "C" void CompilerEtsStObjByNameF32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
322                                           float storeValue)
323 {
324     CompilerEtsStObjByName<panda_file::Type::TypeId::F32, float>(method, id, pc, obj, storeValue);
325 }
326 
CompilerEtsStObjByNameF64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,double storeValue)327 extern "C" void CompilerEtsStObjByNameF64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
328                                           double storeValue)
329 {
330     CompilerEtsStObjByName<panda_file::Type::TypeId::F64, double>(method, id, pc, obj, storeValue);
331 }
332 
CompilerEtsStObjByNameObj(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,ark::ObjectHeader * storeValue)333 extern "C" void CompilerEtsStObjByNameObj(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
334                                           ark::ObjectHeader *storeValue)
335 {
336     CompilerEtsStObjByNameRef(method, id, pc, obj, storeValue);
337 }
338 
CompilerEtsEquals(ObjectHeader * obj1,ObjectHeader * obj2)339 extern "C" uint8_t CompilerEtsEquals(ObjectHeader *obj1, ObjectHeader *obj2)
340 {
341     auto coro = EtsCoroutine::GetCurrent();
342     return static_cast<uint8_t>(EtsReferenceEquals(coro, EtsObject::FromCoreType(obj1), EtsObject::FromCoreType(obj2)));
343 }
344 
CompilerEtsStrictEquals(ObjectHeader * obj1,ObjectHeader * obj2)345 extern "C" uint8_t CompilerEtsStrictEquals(ObjectHeader *obj1, ObjectHeader *obj2)
346 {
347     auto coro = EtsCoroutine::GetCurrent();
348     return static_cast<uint8_t>(
349         EtsReferenceEquals<true>(coro, EtsObject::FromCoreType(obj1), EtsObject::FromCoreType(obj2)));
350 }
351 
CompilerEtsTypeof(ObjectHeader * obj)352 extern "C" EtsString *CompilerEtsTypeof(ObjectHeader *obj)
353 {
354     auto coro = EtsCoroutine::GetCurrent();
355     return EtsReferenceTypeof(coro, EtsObject::FromCoreType(obj));
356 }
357 
CompilerEtsIstrue(ObjectHeader * obj)358 extern "C" uint8_t CompilerEtsIstrue(ObjectHeader *obj)
359 {
360     auto coro = EtsCoroutine::GetCurrent();
361     return static_cast<uint8_t>(EtsIstrue(coro, EtsObject::FromCoreType(obj)));
362 }
363 
CompilerDoubleToStringDecimal(ObjectHeader * cache,uint64_t number,uint64_t unused)364 extern "C" EtsString *CompilerDoubleToStringDecimal(ObjectHeader *cache, uint64_t number,
365                                                     [[maybe_unused]] uint64_t unused)
366 {
367     if (UNLIKELY(cache == nullptr)) {
368         return DoubleToStringCache::GetNoCache(bit_cast<double>(number));
369     }
370     return DoubleToStringCache::FromCoreType(cache)->GetOrCache(EtsCoroutine::GetCurrent(), bit_cast<double>(number));
371 }
372 
373 }  // namespace ark::ets::intrinsics
374