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