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