1 /* 2 * Copyright (c) 2024-2025 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 isStatic,bool allowExternal,uint32_t *)310 FieldPtr ResolveField([[maybe_unused]] MethodPtr method, size_t id, [[maybe_unused]] bool isStatic, 311 [[maybe_unused]] bool allowExternal, 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