• 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>
SetTypedFieldPrimitive(Field * field,const VMHandle<ObjectHeader> & handleObj,T storeValue)181 static void SetTypedFieldPrimitive(Field *field, const VMHandle<ObjectHeader> &handleObj, T storeValue)
182 {
183     switch (field->GetTypeId()) {
184         case panda_file::Type::TypeId::U1:
185         case panda_file::Type::TypeId::U8: {
186             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
187             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint8_t>(storeValue));
188             return;
189         }
190         case panda_file::Type::TypeId::I8: {
191             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
192             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int8_t>(storeValue));
193             return;
194         }
195         case panda_file::Type::TypeId::I16: {
196             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
197             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int16_t>(storeValue));
198             return;
199         }
200         case panda_file::Type::TypeId::U16: {
201             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
202             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint16_t>(storeValue));
203             return;
204         }
205         case panda_file::Type::TypeId::I32: {
206             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
207             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int32_t>(storeValue));
208             return;
209         }
210         case panda_file::Type::TypeId::U32: {
211             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I32);
212             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint32_t>(storeValue));
213             return;
214         }
215         case panda_file::Type::TypeId::I64: {
216             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I64);
217             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<int64_t>(storeValue));
218             return;
219         }
220         case panda_file::Type::TypeId::U64: {
221             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::I64);
222             handleObj.GetPtr()->SetFieldPrimitive(*field, static_cast<uint64_t>(storeValue));
223             return;
224         }
225         case panda_file::Type::TypeId::F32: {
226             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::F32);
227             handleObj.GetPtr()->SetFieldPrimitive(*field, storeValue);
228             return;
229         }
230         case panda_file::Type::TypeId::F64: {
231             ASSERT(FIELD_TYPE == panda_file::Type::TypeId::F64);
232             handleObj.GetPtr()->SetFieldPrimitive(*field, storeValue);
233             return;
234         }
235         default: {
236             UNREACHABLE();
237         }
238     }
239 }
240 
241 template <panda_file::Type::TypeId FIELD_TYPE, class T>
CompilerEtsStObjByName(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,T storeValue)242 void CompilerEtsStObjByName(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj, T storeValue)
243 {
244     ASSERT(method != nullptr);
245     ark::Class *klass;
246     ark::Field *rawField;
247     {
248         auto *thread = ManagedThread::GetCurrent();
249         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
250         VMHandle<ObjectHeader> handleObj(thread, obj);
251         auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
252         klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
253         rawField = classLinker->GetField(*method, panda_file::File::EntityId(id));
254 
255         auto field = TryGetField<FIELD_TYPE>(method, rawField, pc, klass);
256         if (field != nullptr) {
257             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
258                 UNREACHABLE();
259             } else {
260                 SetTypedFieldPrimitive<FIELD_TYPE, T>(field, handleObj, storeValue);
261                 return;
262             }
263         }
264 
265         auto callee = TryGetCallee<FIELD_TYPE, false>(method, rawField, pc, klass);
266         if (callee != nullptr) {
267             PandaVector<Value> args {Value(handleObj.GetPtr()), Value(storeValue)};
268             callee->Invoke(Coroutine::GetCurrent(), args.data());
269             return;
270         }
271     }
272     LookUpException<true>(klass, rawField);
273     UNREACHABLE();
274 }
275 
CompilerEtsStObjByNameRef(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,ark::ObjectHeader * storeValue)276 void CompilerEtsStObjByNameRef(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
277                                ark::ObjectHeader *storeValue)
278 {
279     ASSERT(method != nullptr);
280     ark::Class *klass;
281     ark::Field *rawField;
282     {
283         auto *thread = ManagedThread::GetCurrent();
284         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
285         VMHandle<ObjectHeader> handleObj(thread, obj);
286         VMHandle<ObjectHeader> handleStore(thread, storeValue);
287         auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
288         klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
289         rawField = classLinker->GetField(*method, panda_file::File::EntityId(id));
290 
291         auto field = TryGetField<panda_file::Type::TypeId::REFERENCE>(method, rawField, pc, klass);
292         if (field != nullptr) {
293             return handleObj.GetPtr()->SetFieldObject(*field, handleStore.GetPtr());
294         }
295 
296         auto callee = TryGetCallee<panda_file::Type::TypeId::REFERENCE, false>(method, rawField, pc, klass);
297         if (callee != nullptr) {
298             PandaVector<Value> args {Value(handleObj.GetPtr()), Value(handleStore.GetPtr())};
299             callee->Invoke(Coroutine::GetCurrent(), args.data());
300             return;
301         }
302     }
303     LookUpException<true>(klass, rawField);
304     UNREACHABLE();
305 }
306 
CompilerEtsLdObjByNameI32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)307 extern "C" int32_t CompilerEtsLdObjByNameI32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
308 {
309     return CompilerEtsLdObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj);
310 }
311 
CompilerEtsLdObjByNameI64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)312 extern "C" int64_t CompilerEtsLdObjByNameI64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
313 {
314     return CompilerEtsLdObjByName<panda_file::Type::TypeId::I64, int64_t>(method, id, pc, obj);
315 }
316 
CompilerEtsLdObjByNameF32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)317 extern "C" float CompilerEtsLdObjByNameF32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
318 {
319     return CompilerEtsLdObjByName<panda_file::Type::TypeId::F32, float>(method, id, pc, obj);
320 }
321 
CompilerEtsLdObjByNameF64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)322 extern "C" double CompilerEtsLdObjByNameF64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj)
323 {
324     return CompilerEtsLdObjByName<panda_file::Type::TypeId::F64, double>(method, id, pc, obj);
325 }
326 
CompilerEtsLdObjByNameObj(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj)327 extern "C" ark::ObjectHeader *CompilerEtsLdObjByNameObj(ark::Method *method, int32_t id, uint32_t pc,
328                                                         ark::ObjectHeader *obj)
329 {
330     return CompilerEtsLdObjByName<panda_file::Type::TypeId::REFERENCE, ark::ObjectHeader *>(method, id, pc, obj);
331 }
332 
CompilerEtsStObjByNameI8(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int8_t storeValue)333 extern "C" void CompilerEtsStObjByNameI8(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
334                                          int8_t storeValue)
335 {
336     CompilerEtsStObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj,
337                                                                    static_cast<int32_t>(storeValue));
338 }
339 
CompilerEtsStObjByNameI16(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int16_t storeValue)340 extern "C" void CompilerEtsStObjByNameI16(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
341                                           int16_t storeValue)
342 {
343     CompilerEtsStObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj,
344                                                                    static_cast<int32_t>(storeValue));
345 }
346 
CompilerEtsStObjByNameI32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int32_t storeValue)347 extern "C" void CompilerEtsStObjByNameI32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
348                                           int32_t storeValue)
349 {
350     CompilerEtsStObjByName<panda_file::Type::TypeId::I32, int32_t>(method, id, pc, obj, storeValue);
351 }
352 
CompilerEtsStObjByNameI64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,int64_t storeValue)353 extern "C" void CompilerEtsStObjByNameI64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
354                                           int64_t storeValue)
355 {
356     CompilerEtsStObjByName<panda_file::Type::TypeId::I64, int64_t>(method, id, pc, obj, storeValue);
357 }
358 
CompilerEtsStObjByNameF32(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,float storeValue)359 extern "C" void CompilerEtsStObjByNameF32(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
360                                           float storeValue)
361 {
362     CompilerEtsStObjByName<panda_file::Type::TypeId::F32, float>(method, id, pc, obj, storeValue);
363 }
364 
CompilerEtsStObjByNameF64(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,double storeValue)365 extern "C" void CompilerEtsStObjByNameF64(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
366                                           double storeValue)
367 {
368     CompilerEtsStObjByName<panda_file::Type::TypeId::F64, double>(method, id, pc, obj, storeValue);
369 }
370 
CompilerEtsStObjByNameObj(ark::Method * method,int32_t id,uint32_t pc,ark::ObjectHeader * obj,ark::ObjectHeader * storeValue)371 extern "C" void CompilerEtsStObjByNameObj(ark::Method *method, int32_t id, uint32_t pc, ark::ObjectHeader *obj,
372                                           ark::ObjectHeader *storeValue)
373 {
374     CompilerEtsStObjByNameRef(method, id, pc, obj, storeValue);
375 }
376 
CompilerEtsEquals(ObjectHeader * obj1,ObjectHeader * obj2)377 extern "C" uint8_t CompilerEtsEquals(ObjectHeader *obj1, ObjectHeader *obj2)
378 {
379     auto coro = EtsCoroutine::GetCurrent();
380     return static_cast<uint8_t>(EtsReferenceEquals(coro, EtsObject::FromCoreType(obj1), EtsObject::FromCoreType(obj2)));
381 }
382 
CompilerDoubleToStringDecimal(ObjectHeader * cache,uint64_t number,uint64_t unused)383 extern "C" EtsString *CompilerDoubleToStringDecimal(ObjectHeader *cache, uint64_t number,
384                                                     [[maybe_unused]] uint64_t unused)
385 {
386     ASSERT(cache != nullptr);
387     return DoubleToStringCache::FromCoreType(cache)->GetOrCache(EtsCoroutine::GetCurrent(), bit_cast<double>(number));
388 }
389 
390 }  // namespace ark::ets::intrinsics
391