• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #ifndef LIBABCKIT_SRC_ADAPTER_STATIC_RUNTIME_ADAPTER_STATIC_H
17 #define LIBABCKIT_SRC_ADAPTER_STATIC_RUNTIME_ADAPTER_STATIC_H
18 
19 #include "static_core/compiler/optimizer/ir/runtime_interface.h"
20 #include "static_core/libpandafile/bytecode_instruction.h"
21 #include "static_core/libpandafile/class_data_accessor-inl.h"
22 #include "static_core/libpandafile/code_data_accessor.h"
23 #include "static_core/libpandafile/field_data_accessor.h"
24 #include "static_core/libpandafile/file.h"
25 #include "static_core/libpandafile/file_items.h"
26 #include "static_core/libpandafile/method_data_accessor.h"
27 #include "static_core/libpandafile/proto_data_accessor.h"
28 #include "static_core/libpandafile/proto_data_accessor-inl.h"
29 #include "static_core/libpandafile/type_helper.h"
30 
31 namespace libabckit {
32 using ark::compiler::RuntimeInterface;
33 
34 class AbckitRuntimeAdapterStatic : public RuntimeInterface {
35 public:
AbckitRuntimeAdapterStatic(const ark::panda_file::File & abcFile)36     explicit AbckitRuntimeAdapterStatic(const ark::panda_file::File &abcFile) : abcFile_(abcFile) {}
37     ~AbckitRuntimeAdapterStatic() override = default;
38     NO_COPY_SEMANTIC(AbckitRuntimeAdapterStatic);
39     NO_MOVE_SEMANTIC(AbckitRuntimeAdapterStatic);
40 
GetBinaryFileForMethod(MethodPtr method)41     BinaryFilePtr GetBinaryFileForMethod([[maybe_unused]] MethodPtr method) const override
42     {
43         return const_cast<ark::panda_file::File *>(&abcFile_);
44     }
45 
ResolveMethodIndex(MethodPtr parentMethod,MethodIndex index)46     MethodId ResolveMethodIndex(MethodPtr parentMethod, MethodIndex index) const override
47     {
48         return abcFile_.ResolveMethodIndex(MethodCast(parentMethod), index).GetOffset();
49     }
50 
ResolveFieldIndex(MethodPtr parentMethod,FieldIndex index)51     FieldId ResolveFieldIndex(MethodPtr parentMethod, FieldIndex index) const override
52     {
53         return abcFile_.ResolveFieldIndex(MethodCast(parentMethod), index).GetOffset();
54     }
55 
ResolveTypeIndex(MethodPtr parentMethod,TypeIndex index)56     IdType ResolveTypeIndex(MethodPtr parentMethod, TypeIndex index) const override
57     {
58         return abcFile_.ResolveClassIndex(MethodCast(parentMethod), index).GetOffset();
59     }
60 
GetMethodById(MethodPtr caller,MethodId id)61     MethodPtr GetMethodById([[maybe_unused]] MethodPtr caller, MethodId id) const override
62     {
63         return reinterpret_cast<MethodPtr>(id);
64     }
65 
GetMethodId(MethodPtr method)66     MethodId GetMethodId(MethodPtr method) const override
67     {
68         return static_cast<MethodId>(reinterpret_cast<uintptr_t>(method));
69     }
70 
GetMethodReturnType(MethodPtr method)71     ark::compiler::DataType::Type GetMethodReturnType(MethodPtr method) const override
72     {
73         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
74         ark::panda_file::ProtoDataAccessor pda(abcFile_, mda.GetProtoId());
75 
76         return ToCompilerType(ark::panda_file::GetEffectiveType(pda.GetReturnType()));
77     }
78 
GetMethodReturnTypeId(MethodPtr method)79     IdType GetMethodReturnTypeId(MethodPtr method) const override
80     {
81         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
82         ark::panda_file::ProtoDataAccessor pda(abcFile_, mda.GetProtoId());
83 
84         return pda.GetReferenceType(0).GetOffset();
85     }
86 
GetMethodTotalArgumentType(MethodPtr method,size_t index)87     ark::compiler::DataType::Type GetMethodTotalArgumentType(MethodPtr method, size_t index) const override
88     {
89         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
90 
91         if (!mda.IsStatic()) {
92             if (index == 0) {
93                 return ToCompilerType(
94                     ark::panda_file::GetEffectiveType(ark::panda_file::Type(ark::panda_file::Type::TypeId::REFERENCE)));
95             }
96             --index;
97         }
98 
99         ark::panda_file::ProtoDataAccessor pda(abcFile_, mda.GetProtoId());
100         return ToCompilerType(ark::panda_file::GetEffectiveType(pda.GetArgType(index)));
101     }
102 
GetMethodArgumentType(MethodPtr caller,MethodId id,size_t index)103     ark::compiler::DataType::Type GetMethodArgumentType([[maybe_unused]] MethodPtr caller, MethodId id,
104                                                         size_t index) const override
105     {
106         ark::panda_file::MethodDataAccessor mda(abcFile_, ark::panda_file::File::EntityId(id));
107         ark::panda_file::ProtoDataAccessor pda(abcFile_, mda.GetProtoId());
108 
109         return ToCompilerType(ark::panda_file::GetEffectiveType(pda.GetArgType(index)));
110     }
111 
GetMethodTotalArgumentsCount(MethodPtr method)112     size_t GetMethodTotalArgumentsCount(MethodPtr method) const override
113     {
114         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
115 
116         ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
117         ark::panda_file::CodeDataAccessor cda(abcFile_, mda.GetCodeId().value());
118 
119         return cda.GetNumArgs();
120     }
121 
GetMethodArgumentsCount(MethodPtr caller,MethodId id)122     size_t GetMethodArgumentsCount([[maybe_unused]] MethodPtr caller, MethodId id) const override
123     {
124         ark::panda_file::MethodDataAccessor mda(abcFile_, ark::panda_file::File::EntityId(id));
125         ark::panda_file::ProtoDataAccessor pda(abcFile_, mda.GetProtoId());
126 
127         return pda.GetNumArgs();
128     }
129 
GetMethodReturnType(MethodPtr caller,MethodId id)130     ark::compiler::DataType::Type GetMethodReturnType(MethodPtr caller, MethodId id) const override
131     {
132         return GetMethodReturnType(GetMethodById(caller, id));
133     }
134 
GetMethodRegistersCount(MethodPtr method)135     size_t GetMethodRegistersCount(MethodPtr method) const override
136     {
137         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
138 
139         ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
140         ark::panda_file::CodeDataAccessor cda(abcFile_, mda.GetCodeId().value());
141 
142         return cda.GetNumVregs();
143     }
144 
GetMethodCode(MethodPtr method)145     const uint8_t *GetMethodCode(MethodPtr method) const override
146     {
147         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
148 
149         ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
150         ark::panda_file::CodeDataAccessor cda(abcFile_, mda.GetCodeId().value());
151 
152         return cda.GetInstructions();
153     }
154 
GetMethodCodeSize(MethodPtr method)155     size_t GetMethodCodeSize(MethodPtr method) const override
156     {
157         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
158 
159         ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
160         ark::panda_file::CodeDataAccessor cda(abcFile_, mda.GetCodeId().value());
161 
162         return cda.GetCodeSize();
163     }
164 
GetMethodSourceLanguage(MethodPtr method)165     ark::SourceLanguage GetMethodSourceLanguage(MethodPtr method) const override
166     {
167         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
168 
169         ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
170 
171         auto sourceLang = mda.GetSourceLang();
172         ASSERT(sourceLang.has_value());
173 
174         return static_cast<ark::SourceLanguage>(sourceLang.value());
175     }
176 
GetClassIdForField(MethodPtr method,size_t fieldId)177     size_t GetClassIdForField([[maybe_unused]] MethodPtr method, size_t fieldId) const override
178     {
179         ark::panda_file::FieldDataAccessor fda(abcFile_, ark::panda_file::File::EntityId(fieldId));
180 
181         return static_cast<size_t>(fda.GetClassId().GetOffset());
182     }
183 
GetClassForField(FieldPtr field)184     ClassPtr GetClassForField(FieldPtr field) const override
185     {
186         ark::panda_file::FieldDataAccessor fda(abcFile_, FieldCast(field));
187 
188         return reinterpret_cast<ClassPtr>(fda.GetClassId().GetOffset());
189     }
190 
GetClassIdForMethod(MethodPtr method)191     uint32_t GetClassIdForMethod(MethodPtr method) const override
192     {
193         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
194 
195         return static_cast<size_t>(mda.GetClassId().GetOffset());
196     }
197 
GetClassIdForMethod(MethodPtr caller,size_t methodId)198     uint32_t GetClassIdForMethod([[maybe_unused]] MethodPtr caller, size_t methodId) const override
199     {
200         ark::panda_file::MethodDataAccessor mda(abcFile_, ark::panda_file::File::EntityId(methodId));
201 
202         return static_cast<size_t>(mda.GetClassId().GetOffset());
203     }
204 
IsMethodExternal(MethodPtr caller,MethodPtr callee)205     bool IsMethodExternal([[maybe_unused]] MethodPtr caller, MethodPtr callee) const override
206     {
207         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(callee));
208 
209         return mda.IsExternal();
210     }
211 
IsMethodIntrinsic(MethodPtr method)212     bool IsMethodIntrinsic([[maybe_unused]] MethodPtr method) const override
213     {
214         return false;
215     }
216 
IsMethodIntrinsic(MethodPtr caller,MethodId id)217     bool IsMethodIntrinsic([[maybe_unused]] MethodPtr caller, [[maybe_unused]] MethodId id) const override
218     {
219         return false;
220     }
221 
GetIntrinsicId(MethodPtr method)222     IntrinsicId GetIntrinsicId([[maybe_unused]] MethodPtr method) const override
223     {
224         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
225         auto className = GetClassNameFromMethod(method);
226         auto methodName = GetMethodName(method);
227         return GetIntrinsicId(className, methodName, mda);
228     }
229 
IsMethodStatic(MethodPtr method)230     bool IsMethodStatic(MethodPtr method) const override
231     {
232         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
233 
234         return mda.IsStatic();
235     }
236 
IsMethodStatic(MethodPtr caller,MethodId id)237     bool IsMethodStatic([[maybe_unused]] MethodPtr caller, MethodId id) const override
238     {
239         ark::panda_file::MethodDataAccessor mda(abcFile_, ark::panda_file::File::EntityId(id));
240 
241         return mda.IsStatic();
242     }
243 
244     // return true if the method is Native with exception
HasNativeException(MethodPtr method)245     bool HasNativeException([[maybe_unused]] MethodPtr method) const override
246     {
247         return false;
248     }
249 
GetClassNameFromMethod(MethodPtr method)250     std::string GetClassNameFromMethod(MethodPtr method) const override
251     {
252         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
253 
254         return mda.GetClassName();
255     }
256 
GetClassName(ClassPtr cls)257     std::string GetClassName(ClassPtr cls) const override
258     {
259         auto stringData = abcFile_.GetStringData(ClassCast(cls));
260 
261         return ark::panda_file::ClassDataAccessor::DemangledName(stringData);
262     }
263 
GetMethodName(MethodPtr method)264     std::string GetMethodName(MethodPtr method) const override
265     {
266         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
267 
268         auto stringData = abcFile_.GetStringData(mda.GetNameId());
269 
270         return std::string(reinterpret_cast<const char *>(stringData.data));
271     }
272 
IsConstructor(MethodPtr method,ark::SourceLanguage lang)273     bool IsConstructor(MethodPtr method, ark::SourceLanguage lang) override
274     {
275         return GetMethodName(method) == ark::panda_file::GetCtorName(lang);
276     }
277 
GetMethodFullName(MethodPtr method,bool)278     std::string GetMethodFullName(MethodPtr method, bool /* with_signature */) const override
279     {
280         auto className = GetClassNameFromMethod(method);
281         auto methodName = GetMethodName(method);
282 
283         return className + "::" + methodName;
284     }
285 
GetClass(MethodPtr method)286     ClassPtr GetClass(MethodPtr method) const override
287     {
288         ark::panda_file::MethodDataAccessor mda(abcFile_, MethodCast(method));
289 
290         return reinterpret_cast<ClassPtr>(mda.GetClassId().GetOffset());
291     }
292 
GetBytecodeString(MethodPtr method,uintptr_t pc)293     std::string GetBytecodeString(MethodPtr method, uintptr_t pc) const override
294     {
295         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
296         ark::BytecodeInstruction inst(GetMethodCode(method) + pc);
297         std::stringstream ss;
298 
299         ss << inst;
300         return ss.str();
301     }
302 
IsArrayClass(MethodPtr method,IdType id)303     bool IsArrayClass([[maybe_unused]] MethodPtr method, IdType id) const override
304     {
305         ark::panda_file::File::EntityId cid(id);
306 
307         return ark::panda_file::IsArrayDescriptor(abcFile_.GetStringData(cid).data);
308     }
309 
ResolveField(MethodPtr method,size_t id,bool allowExternal,uint32_t *)310     FieldPtr ResolveField([[maybe_unused]] MethodPtr method, size_t id, [[maybe_unused]] bool allowExternal,
311                           uint32_t * /* class_id */) override
312     {
313         return reinterpret_cast<FieldPtr>(id);
314     }
315 
GetFieldType(FieldPtr field)316     ark::compiler::DataType::Type GetFieldType(FieldPtr field) const override
317     {
318         ark::panda_file::FieldDataAccessor fda(abcFile_, FieldCast(field));
319 
320         return ToCompilerType(ark::panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
321     }
322 
GetFieldTypeById(MethodPtr parentMethod,IdType id)323     ark::compiler::DataType::Type GetFieldTypeById([[maybe_unused]] MethodPtr parentMethod, IdType id) const override
324     {
325         ark::panda_file::FieldDataAccessor fda(abcFile_, ark::panda_file::File::EntityId(id));
326 
327         return ToCompilerType(ark::panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
328     }
329 
GetFieldValueTypeId(MethodPtr method,IdType id)330     IdType GetFieldValueTypeId([[maybe_unused]] MethodPtr method, IdType id) const override
331     {
332         auto typeId = ark::panda_file::FieldDataAccessor::GetTypeId(abcFile_, ark::panda_file::File::EntityId(id));
333         return typeId.GetOffset();
334     }
335 
EnumerateCDAFields(ark::panda_file::File::EntityId & fieldId,ark::panda_file::FieldDataAccessor & fda,ark::panda_file::FieldDataAccessor & fieldDataAccessor)336     static ark::panda_file::File::EntityId EnumerateCDAFields(ark::panda_file::File::EntityId &fieldId,
337                                                               ark::panda_file::FieldDataAccessor &fda,
338                                                               ark::panda_file::FieldDataAccessor &fieldDataAccessor)
339     {
340         auto &pf = fda.GetPandaFile();
341         auto fieldType = ark::panda_file::Type::GetTypeFromFieldEncoding(fda.GetType());
342         if (fda.GetType() != fieldDataAccessor.GetType()) {
343             return fieldId;
344         }
345 
346         if (pf.GetStringData(fda.GetNameId()) != pf.GetStringData(fieldDataAccessor.GetNameId())) {
347             return fieldId;
348         }
349 
350         if (fieldType.IsReference()) {
351             if (pf.GetStringData(ark::panda_file::File::EntityId(fda.GetType())) !=
352                 pf.GetStringData(ark::panda_file::File::EntityId(fieldDataAccessor.GetType()))) {
353                 return fieldId;
354             }
355         }
356 
357         return fieldDataAccessor.GetFieldId();
358     }
359 
IsFieldVolatile(FieldPtr field)360     bool IsFieldVolatile(FieldPtr field) const override
361     {
362         ark::panda_file::FieldDataAccessor fda(abcFile_, FieldCast(field));
363 
364         if (!fda.IsExternal()) {
365             return fda.IsVolatile();
366         }
367 
368         auto fieldId = ark::panda_file::File::EntityId();
369 
370         if (abcFile_.IsExternal(fda.GetClassId())) {
371             // If the field is external and class of the field is also external
372             // assume that field is volatile
373             return true;
374         }
375 
376         auto classId = ark::panda_file::ClassDataAccessor(abcFile_, fda.GetClassId()).GetSuperClassId();
377 #ifndef NDEBUG
378         auto visitedClasses = std::unordered_set<ark::panda_file::File::EntityId> {classId};
379 #endif
380         while (classId.IsValid() && !abcFile_.IsExternal(classId)) {
381             auto cda = ark::panda_file::ClassDataAccessor(abcFile_, classId);
382             cda.EnumerateFields([&fieldId, &fda](ark::panda_file::FieldDataAccessor &fieldDataAccessor) {
383                 fieldId = EnumerateCDAFields(fieldId, fda, fieldDataAccessor);
384             });
385 
386             classId = cda.GetSuperClassId();
387 #ifndef NDEBUG
388             ASSERT_PRINT(visitedClasses.count(classId) == 0, "Class hierarchy is incorrect");
389             visitedClasses.insert(classId);
390 #endif
391         }
392 
393         if (!fieldId.IsValid()) {
394             // If we cannot find field (for example it's in the class that located in other panda file)
395             // assume that field is volatile
396             return true;
397         }
398         ASSERT(fieldId.IsValid());
399         ark::panda_file::FieldDataAccessor fieldDa(abcFile_, fieldId);
400         return fieldDa.IsVolatile();
401     }
402 
ResolveType(MethodPtr method,size_t id)403     ClassPtr ResolveType([[maybe_unused]] MethodPtr method, size_t id) const override
404     {
405         return reinterpret_cast<ClassPtr>(id);
406     }
407 
GetFieldName(FieldPtr field)408     std::string GetFieldName(FieldPtr field) const override
409     {
410         ark::panda_file::FieldDataAccessor fda(abcFile_, FieldCast(field));
411         auto stringData = abcFile_.GetStringData(fda.GetNameId());
412         return ark::utf::Mutf8AsCString(stringData.data);
413     }
414 
415 private:
ToCompilerType(ark::panda_file::Type type)416     static ark::compiler::DataType::Type ToCompilerType(ark::panda_file::Type type)
417     {
418         switch (type.GetId()) {
419             case ark::panda_file::Type::TypeId::VOID:
420                 return ark::compiler::DataType::VOID;
421             case ark::panda_file::Type::TypeId::U1:
422                 return ark::compiler::DataType::BOOL;
423             case ark::panda_file::Type::TypeId::I8:
424                 return ark::compiler::DataType::INT8;
425             case ark::panda_file::Type::TypeId::U8:
426                 return ark::compiler::DataType::UINT8;
427             case ark::panda_file::Type::TypeId::I16:
428                 return ark::compiler::DataType::INT16;
429             case ark::panda_file::Type::TypeId::U16:
430                 return ark::compiler::DataType::UINT16;
431             case ark::panda_file::Type::TypeId::I32:
432                 return ark::compiler::DataType::INT32;
433             case ark::panda_file::Type::TypeId::U32:
434                 return ark::compiler::DataType::UINT32;
435             case ark::panda_file::Type::TypeId::I64:
436                 return ark::compiler::DataType::INT64;
437             case ark::panda_file::Type::TypeId::U64:
438                 return ark::compiler::DataType::UINT64;
439             case ark::panda_file::Type::TypeId::F32:
440                 return ark::compiler::DataType::FLOAT32;
441             case ark::panda_file::Type::TypeId::F64:
442                 return ark::compiler::DataType::FLOAT64;
443             case ark::panda_file::Type::TypeId::REFERENCE:
444                 return ark::compiler::DataType::REFERENCE;
445             case ark::panda_file::Type::TypeId::TAGGED:
446             case ark::panda_file::Type::TypeId::INVALID:
447                 return ark::compiler::DataType::ANY;
448             default:
449                 break;
450         }
451         UNREACHABLE();
452     }
453 
MethodCast(RuntimeInterface::MethodPtr method)454     static ark::panda_file::File::EntityId MethodCast(RuntimeInterface::MethodPtr method)
455     {
456         return ark::panda_file::File::EntityId(reinterpret_cast<uintptr_t>(method));
457     }
458 
ClassCast(RuntimeInterface::ClassPtr cls)459     static ark::panda_file::File::EntityId ClassCast(RuntimeInterface::ClassPtr cls)
460     {
461         return ark::panda_file::File::EntityId(reinterpret_cast<uintptr_t>(cls));
462     }
463 
FieldCast(RuntimeInterface::FieldPtr field)464     static ark::panda_file::File::EntityId FieldCast(RuntimeInterface::FieldPtr field)
465     {
466         return ark::panda_file::File::EntityId(reinterpret_cast<uintptr_t>(field));
467     }
468 
469     static IntrinsicId GetIntrinsicId(std::string_view className, std::string_view methodName,
470                                       ark::panda_file::MethodDataAccessor mda);
471 
472     static bool IsEqual(ark::panda_file::MethodDataAccessor mda,
473                         std::initializer_list<ark::panda_file::Type::TypeId> shorties,
474                         std::initializer_list<std::string_view> refTypes);
475 
476     const ark::panda_file::File &abcFile_;
477 };
478 }  // namespace libabckit
479 
480 #endif  // LIBABCKIT_SRC_ADAPTER_STATIC_RUNTIME_ADAPTER_STATIC_H
481