1 /**
2 * Copyright (c) 2021-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 #include "plugins/ets/runtime/ets_utils.h"
17 #include "plugins/ets/runtime/types/ets_class.h"
18 #include "plugins/ets/runtime/types/ets_field.h"
19 #include "plugins/ets/runtime/types/ets_method.h"
20
21 namespace ark::ets {
22
IsEtsGlobalClassName(const std::string & descriptor)23 bool IsEtsGlobalClassName(const std::string &descriptor)
24 {
25 ASSERT(descriptor.length() >= 2U); // L...;
26 ASSERT('L' == descriptor[0]);
27 ASSERT(';' == descriptor[descriptor.size() - 1]);
28
29 constexpr size_t ETSGLOBAL_SEMICOLON_LENGTH = sizeof(ETSGLOBAL_CLASS_NAME);
30
31 const auto etsGlobalSubstringPos = descriptor.rfind(ETSGLOBAL_CLASS_NAME);
32 if (etsGlobalSubstringPos == std::string::npos) {
33 return false;
34 }
35 const bool etsGlobalClass = (1 == etsGlobalSubstringPos) && descriptor.length() == 1 + ETSGLOBAL_SEMICOLON_LENGTH;
36 const bool endsWithETSGLOBAL = descriptor.length() - ETSGLOBAL_SEMICOLON_LENGTH == etsGlobalSubstringPos;
37 const bool etsGlobalClassInPackage = endsWithETSGLOBAL && '/' == descriptor[etsGlobalSubstringPos - 1];
38
39 return etsGlobalClass || etsGlobalClassInPackage;
40 }
41
InvokeVoid(EtsCoroutine * coro,EtsObject * lambda)42 void LambdaUtils::InvokeVoid(EtsCoroutine *coro, EtsObject *lambda)
43 {
44 ASSERT(lambda != nullptr);
45 EtsMethod *invoke = lambda->GetClass()->GetInstanceMethod(INVOKE_METHOD_NAME, nullptr);
46 if (invoke == nullptr) {
47 LOG(FATAL, RUNTIME) << "No method '$_invoke' found";
48 return;
49 }
50 Value arg(lambda->GetCoreType());
51 invoke->GetPandaMethod()->InvokeVoid(coro, &arg);
52 }
53
GetDisplayNameStringFromField(EtsField * field)54 EtsString *ManglingUtils::GetDisplayNameStringFromField(EtsField *field)
55 {
56 auto fieldNameData = field->GetCoreType()->GetName();
57 auto fieldNameLength = fieldNameData.utf16Length;
58 std::string_view fieldName(utf::Mutf8AsCString(fieldNameData.data), fieldNameLength);
59 if (fieldName.rfind(PROPERTY, 0) == 0) {
60 ASSERT(fieldNameLength >= PROPERTY_PREFIX_LENGTH);
61 return EtsString::Resolve(
62 fieldNameData.data + PROPERTY_PREFIX_LENGTH, // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
63 fieldNameLength - PROPERTY_PREFIX_LENGTH);
64 }
65 return EtsString::Resolve(fieldNameData.data, fieldNameData.utf16Length);
66 }
67
GetFieldIDByDisplayName(EtsClass * klass,const PandaString & name,const char * sig)68 EtsField *ManglingUtils::GetFieldIDByDisplayName(EtsClass *klass, const PandaString &name, const char *sig)
69 {
70 auto u8name = utf::CStringAsMutf8(name.c_str());
71 auto *field = EtsField::FromRuntimeField(klass->GetRuntimeClass()->GetInstanceFieldByName(u8name));
72 if (field == nullptr && !klass->GetRuntimeClass()->GetInterfaces().empty()) {
73 auto mangledName = PandaString(PROPERTY) + name;
74 u8name = utf::CStringAsMutf8(mangledName.c_str());
75 field = EtsField::FromRuntimeField(klass->GetRuntimeClass()->GetInstanceFieldByName(u8name));
76 }
77
78 if (sig != nullptr && field != nullptr) {
79 auto fieldTypeDescriptor = reinterpret_cast<const uint8_t *>(field->GetTypeDescriptor());
80 if (utf::CompareMUtf8ToMUtf8(fieldTypeDescriptor, reinterpret_cast<const uint8_t *>(sig)) != 0) {
81 return nullptr;
82 }
83 }
84
85 return field;
86 }
87
ExtractClassDescriptorsFromArray(const panda_file::File * pfile,const panda_file::ArrayValue & classesArray,std::vector<std::string> & outDescriptors)88 static void ExtractClassDescriptorsFromArray(const panda_file::File *pfile, const panda_file::ArrayValue &classesArray,
89 std::vector<std::string> &outDescriptors)
90 {
91 const uint32_t valCount = classesArray.GetCount();
92 outDescriptors.resize(valCount);
93 for (uint32_t j = 0; j < valCount; j++) {
94 auto entityId = classesArray.Get<panda_file::File::EntityId>(j);
95 panda_file::ClassDataAccessor classData(*pfile, entityId);
96 outDescriptors[j] = utf::Mutf8AsCString(classData.GetDescriptor());
97 }
98 }
99
100 // NOLINT(clang-analyzer-core) // false positive: this is a function, not a global var
GetExportedClassDescriptorsFromModule(ark::ets::EtsClass * etsGlobalClass,std::vector<std::string> & outDescriptors)101 bool GetExportedClassDescriptorsFromModule(ark::ets::EtsClass *etsGlobalClass, std::vector<std::string> &outDescriptors)
102 {
103 ASSERT(etsGlobalClass != nullptr);
104
105 const auto *runtimeClass = etsGlobalClass->GetRuntimeClass();
106 const panda_file::File *pfile = runtimeClass->GetPandaFile();
107 panda_file::ClassDataAccessor cda(*pfile, runtimeClass->GetFileId());
108
109 bool found = false;
110 cda.EnumerateAnnotation(panda_file_items::class_descriptors::ANNOTATION_MODULE.data(),
111 [&outDescriptors, &found, pfile](panda_file::AnnotationDataAccessor &annotationAccessor) {
112 const uint32_t count = annotationAccessor.GetCount();
113 for (uint32_t i = 0; i < count; i++) {
114 auto elem = annotationAccessor.GetElement(i);
115 std::string nameStr =
116 utf::Mutf8AsCString(pfile->GetStringData(elem.GetNameId()).data);
117 if (nameStr == panda_file_items::class_descriptors::ANNOTATION_MODULE_EXPORTED) {
118 auto classesArray = elem.GetArrayValue();
119 ExtractClassDescriptorsFromArray(pfile, classesArray, outDescriptors);
120 found = true;
121 break;
122 }
123 }
124 return true;
125 });
126
127 return found;
128 }
129
130 } // namespace ark::ets
131