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