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