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 #include "abckit_static.h"
17 #include "libabckit/include/c/metadata_core.h"
18 #include "libabckit/src/adapter_static/helpers_static.h"
19 #include "libabckit/include/c/ir_core.h"
20 #include "libabckit/src/statuses_impl.h"
21 #include "libabckit/src/metadata_inspect_impl.h"
22 #include "libabckit/src/adapter_static/runtime_adapter_static.h"
23 #include "libabckit/src/logger.h"
24 #include "libpandafile/file.h"
25
26 #include "src/adapter_static/metadata_modify_static.h"
27
28 #include "static_core/abc2program/abc2program_driver.h"
29
30 #include "static_core/assembler/assembly-emitter.h"
31
32 #include <cstdint>
33 #include <memory>
34 #include <unordered_map>
35
36 // CC-OFFNXT(WordsTool.95 Google) sensitive word conflict
37 // NOLINTNEXTLINE(google-build-using-namespace)
38 using namespace ark;
39
40 namespace libabckit {
41
IsAbstract(pandasm::ItemMetadata * meta)42 static bool IsAbstract(pandasm::ItemMetadata *meta)
43 {
44 uint32_t flags = meta->GetAccessFlags();
45 return (flags & ACC_ABSTRACT) != 0U;
46 }
47
CreateNameString(AbckitFile * file,std::string & name)48 AbckitString *CreateNameString(AbckitFile *file, std::string &name)
49 {
50 return CreateStringStatic(file, name.data(), name.size());
51 }
52
FunctionGetImpl(AbckitCoreFunction * function)53 pandasm::Function *FunctionGetImpl(AbckitCoreFunction *function)
54 {
55 return function->GetArkTSImpl()->GetStaticImpl();
56 }
57
DumpHierarchy(AbckitFile * file)58 static void DumpHierarchy(AbckitFile *file)
59 {
60 std::function<void(AbckitCoreFunction * f, const std::string &indent)> dumpFunc;
61 std::function<void(AbckitCoreClass * c, const std::string &indent)> dumpClass;
62
63 dumpFunc = [&dumpFunc, &dumpClass](AbckitCoreFunction *f, const std::string &indent = "") {
64 auto fName = FunctionGetImpl(f)->name;
65 LIBABCKIT_LOG_NO_FUNC(DEBUG) << indent << fName << std::endl;
66 for (auto &cNested : f->nestedClasses) {
67 dumpClass(cNested.get(), indent + " ");
68 }
69 for (auto &fNested : f->nestedFunction) {
70 dumpFunc(fNested.get(), indent + " ");
71 }
72 };
73
74 dumpClass = [&dumpFunc](AbckitCoreClass *c, const std::string &indent = "") {
75 auto cName = c->GetArkTSImpl()->impl.GetStaticClass()->name;
76 LIBABCKIT_LOG_NO_FUNC(DEBUG) << indent << cName << std::endl;
77 for (auto &f : c->methods) {
78 dumpFunc(f.get(), indent + " ");
79 }
80 };
81
82 std::function<void(AbckitCoreNamespace * n, const std::string &indent)> dumpNamespace =
83 [&dumpFunc, &dumpClass, &dumpNamespace](AbckitCoreNamespace *n, const std::string &indent = "") {
84 ASSERT(n->owningModule->target == ABCKIT_TARGET_ARK_TS_V1);
85 auto &nName = FunctionGetImpl(n->GetArkTSImpl()->f.get())->name;
86 LIBABCKIT_LOG_NO_FUNC(DEBUG) << indent << nName << std::endl;
87 for (auto &n : n->namespaces) {
88 dumpNamespace(n.get(), indent + " ");
89 }
90 for (auto &c : n->classes) {
91 dumpClass(c.get(), indent + " ");
92 }
93 for (auto &f : n->functions) {
94 dumpFunc(f.get(), indent + " ");
95 }
96 };
97
98 for (auto &[mName, m] : file->localModules) {
99 LIBABCKIT_LOG_NO_FUNC(DEBUG) << mName << std::endl;
100 for (auto &n : m->namespaces) {
101 dumpNamespace(n.get(), "");
102 }
103 for (auto &[cName, c] : m->ct) {
104 dumpClass(c.get(), "");
105 }
106 for (auto &f : m->functions) {
107 dumpFunc(f.get(), "");
108 }
109 }
110 }
111
CollectFunction(AbckitFile * file,std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,const std::string & functionName,ark::pandasm::Function & functionImpl)112 std::unique_ptr<AbckitCoreFunction> CollectFunction(
113 AbckitFile *file, std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
114 const std::string &functionName, ark::pandasm::Function &functionImpl)
115 {
116 auto [moduleName, className] = FuncGetNames(functionName);
117 LIBABCKIT_LOG(DEBUG) << " Found function. module: '" << moduleName << "' class: '" << className << "' function: '"
118 << functionName << "'\n";
119 ASSERT(nameToModule.find(moduleName) != nameToModule.end());
120 auto &functionModule = nameToModule[moduleName];
121 auto function = std::make_unique<AbckitCoreFunction>();
122 function->owningModule = functionModule.get();
123 function->impl = std::make_unique<AbckitArktsFunction>();
124 function->GetArkTSImpl()->impl = &functionImpl;
125 function->GetArkTSImpl()->core = function.get();
126 auto name = GetMangleFuncName(function.get());
127 auto &nameToFunction = functionImpl.IsStatic() ? file->nameToFunctionStatic : file->nameToFunctionInstance;
128 ASSERT(nameToFunction.count(name) == 0);
129 nameToFunction.insert({name, function.get()});
130
131 for (auto &annoImpl : functionImpl.metadata->GetAnnotations()) {
132 auto anno = std::make_unique<AbckitCoreAnnotation>();
133 anno->impl = std::make_unique<AbckitArktsAnnotation>();
134 anno->GetArkTSImpl()->core = anno.get();
135
136 for (auto &annoElemImpl : annoImpl.GetElements()) {
137 auto annoElem = std::make_unique<AbckitCoreAnnotationElement>();
138 annoElem->ann = anno.get();
139 auto annoElemImplName = annoElemImpl.GetName();
140 annoElem->name = CreateStringStatic(file, annoElemImplName.data(), annoElemImplName.size());
141 annoElem->impl = std::make_unique<AbckitArktsAnnotationElement>();
142 annoElem->GetArkTSImpl()->core = annoElem.get();
143 auto value = FindOrCreateValueStatic(file, *annoElemImpl.GetValue());
144 annoElem->value = value;
145
146 anno->elements.emplace_back(std::move(annoElem));
147 }
148 function->annotations.emplace_back(std::move(anno));
149 }
150
151 return function;
152 }
153
CreateModule(AbckitFile * file,std::unordered_set<std::string> & globalClassNames,std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,const std::string & recordName)154 static void CreateModule(AbckitFile *file, std::unordered_set<std::string> &globalClassNames,
155 std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
156 const std::string &recordName)
157 {
158 auto [moduleName, className] = ClassGetNames(recordName);
159 if (globalClassNames.find(className) != globalClassNames.end()) {
160 if (nameToModule.find(moduleName) != nameToModule.end()) {
161 LIBABCKIT_LOG(FATAL) << "Duplicated ETSGLOBAL for module: " << moduleName << '\n';
162 }
163
164 LIBABCKIT_LOG(DEBUG) << "Found module: '" << moduleName << "'\n";
165 auto m = std::make_unique<AbckitCoreModule>();
166 m->file = file;
167 m->target = ABCKIT_TARGET_ARK_TS_V2;
168 m->moduleName = CreateStringStatic(file, moduleName.data(), moduleName.size());
169 m->impl = std::make_unique<AbckitArktsModule>();
170 m->GetArkTSImpl()->core = m.get();
171 nameToModule.insert({moduleName, std::move(m)});
172 }
173 }
174
CreateClass(std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,const std::string & moduleName,const std::string & className,ark::pandasm::Record & record)175 std::unique_ptr<AbckitCoreClass> CreateClass(
176 std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule, const std::string &moduleName,
177 const std::string &className, ark::pandasm::Record &record)
178 {
179 LIBABCKIT_LOG(DEBUG) << " Found class. module: '" << moduleName << "' class: '" << className << "'\n";
180 ASSERT(nameToModule.find(moduleName) != nameToModule.end());
181 auto &classModule = nameToModule[moduleName];
182 auto abckitRecord = &record;
183 auto klass = std::make_unique<AbckitCoreClass>(classModule.get(), AbckitArktsClass(abckitRecord));
184 return klass;
185 }
186
AssignClasses(std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,std::vector<std::unique_ptr<AbckitCoreClass>> & classes)187 static void AssignClasses(std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
188 std::vector<std::unique_ptr<AbckitCoreClass>> &classes)
189 {
190 for (auto &klass : classes) {
191 auto fullName = klass->GetArkTSImpl()->impl.GetStaticClass()->name;
192 auto [moduleName, className] = ClassGetNames(fullName);
193 LIBABCKIT_LOG(DEBUG) << "moduleName, className, fullName: " << moduleName << ", " << className << ", "
194 << fullName << '\n';
195 auto &classModule = nameToModule[moduleName];
196 classModule->InsertClass(className, std::move(klass));
197 }
198 }
199
AssignFunctions(std::unordered_set<std::string> & globalClassNames,std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,std::unordered_map<std::string,AbckitCoreClass * > & nameToClass,std::vector<std::unique_ptr<AbckitCoreFunction>> & functions)200 static void AssignFunctions(std::unordered_set<std::string> &globalClassNames,
201 std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
202 [[maybe_unused]] std::unordered_map<std::string, AbckitCoreClass *> &nameToClass,
203 std::vector<std::unique_ptr<AbckitCoreFunction>> &functions)
204 {
205 for (auto &function : functions) {
206 std::string functionName = FunctionGetImpl(function.get())->name;
207 auto [moduleName, className] = FuncGetNames(functionName);
208 auto &functionModule = nameToModule[moduleName];
209 if (globalClassNames.find(className) != globalClassNames.end()) {
210 functionModule->functions.emplace_back(std::move(function));
211 } else {
212 ASSERT(functionModule->ct.find(className) != functionModule->ct.end());
213 auto &klass = functionModule->ct[className];
214 function->parentClass = klass.get();
215 klass->methods.emplace_back(std::move(function));
216 }
217 }
218 }
219
220 static const std::string LAMBDA_RECORD_KEY = "LambdaObject";
221 static const std::string INIT_FUNC_NAME = "_$init$_";
222 static const std::string TRIGGER_CCTOR_FUNC_NAME = "_$trigger_cctor$_";
223
ShouldCreateFuncWrapper(pandasm::Function & functionImpl,const std::string & className,const std::string & functionName)224 static bool ShouldCreateFuncWrapper(pandasm::Function &functionImpl, const std::string &className,
225 const std::string &functionName)
226 {
227 if (functionImpl.metadata->IsForeign() || (className.substr(0, LAMBDA_RECORD_KEY.size()) == LAMBDA_RECORD_KEY) ||
228 (functionName.find(INIT_FUNC_NAME, 0) != std::string::npos) ||
229 (functionName.find(TRIGGER_CCTOR_FUNC_NAME, 0) != std::string::npos)) {
230 // NOTE: find and fill AbckitCoreImportDescriptor
231 return false;
232 }
233
234 if (IsAbstract(functionImpl.metadata.get())) {
235 // NOTE: ?
236 return false;
237 }
238
239 return true;
240 }
241
CreateWrappers(pandasm::Program * prog,AbckitFile * file)242 static void CreateWrappers(pandasm::Program *prog, AbckitFile *file)
243 {
244 std::unordered_set<std::string> globalClassNames = {"ETSGLOBAL", "_GLOBAL"};
245 file->program = prog;
246
247 // Collect modules
248 std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> nameToModule;
249 for (auto &[recordName, record] : prog->recordTable) {
250 if (record.metadata->IsForeign()) {
251 // NOTE: Create AbckitCoreImportDescriptor and AbckitCoreModuleDescriptor
252 continue;
253 }
254 CreateModule(file, globalClassNames, nameToModule, recordName);
255 }
256
257 // Collect classes
258 std::vector<std::unique_ptr<AbckitCoreClass>> classes;
259 std::unordered_map<std::string, AbckitCoreClass *> nameToClass;
260 for (auto &[recordName, record] : prog->recordTable) {
261 if (record.metadata->IsForeign() || (recordName.find(LAMBDA_RECORD_KEY) != std::string::npos)) {
262 // NOTE: find and fill AbckitCoreImportDescriptor
263 continue;
264 }
265
266 // NOTE: AbckitCoreAnnotationInterface
267
268 auto [moduleName, className] = ClassGetNames(recordName);
269 if (globalClassNames.find(className) != globalClassNames.end()) {
270 continue;
271 }
272 classes.emplace_back(CreateClass(nameToModule, moduleName, className, record));
273 nameToClass[recordName] = classes.back().get();
274 }
275
276 // Functions
277 std::vector<std::unique_ptr<AbckitCoreFunction>> functions;
278 for (auto &[functionName, functionImpl] : prog->functionStaticTable) {
279 auto [moduleName, className] = FuncGetNames(functionName);
280
281 if (ShouldCreateFuncWrapper(functionImpl, className, functionName)) {
282 functions.emplace_back(CollectFunction(file, nameToModule, functionName, functionImpl));
283 }
284 }
285 for (auto &[functionName, functionImpl] : prog->functionInstanceTable) {
286 auto [moduleName, className] = FuncGetNames(functionName);
287
288 if (ShouldCreateFuncWrapper(functionImpl, className, functionName)) {
289 functions.emplace_back(CollectFunction(file, nameToModule, functionName, functionImpl));
290 }
291 }
292
293 AssignClasses(nameToModule, classes);
294 AssignFunctions(globalClassNames, nameToModule, nameToClass, functions);
295
296 // NOTE: AbckitCoreExportDescriptor
297 // NOTE: AbckitModulePayload
298
299 for (auto &[moduleName, module] : nameToModule) {
300 file->localModules.insert({moduleName, std::move(module)});
301 }
302
303 DumpHierarchy(file);
304
305 // Strings
306 for (auto &sImpl : prog->strings) {
307 auto s = std::make_unique<AbckitString>();
308 s->impl = sImpl;
309 file->strings.insert({sImpl, std::move(s)});
310 }
311 }
312
313 struct CtxIInternal {
314 ark::abc2program::Abc2ProgramDriver *driver = nullptr;
315 };
316
OpenAbcStatic(const char * path,size_t len)317 AbckitFile *OpenAbcStatic(const char *path, size_t len)
318 {
319 LIBABCKIT_LOG_FUNC;
320 auto spath = std::string(path, len);
321 LIBABCKIT_LOG(DEBUG) << spath << '\n';
322 auto *abc2program = new ark::abc2program::Abc2ProgramDriver();
323 if (!abc2program->Compile(spath)) {
324 LIBABCKIT_LOG(DEBUG) << "Failed to open " << spath << "\n";
325 delete abc2program;
326 return nullptr;
327 }
328 pandasm::Program &prog = abc2program->GetProgram();
329 auto file = new AbckitFile();
330 file->frontend = Mode::STATIC;
331 CreateWrappers(&prog, file);
332
333 auto pf = panda_file::File::Open(spath);
334 if (pf == nullptr) {
335 LIBABCKIT_LOG(DEBUG) << "Failed to panda_file::File::Open\n";
336 delete abc2program;
337 delete file;
338 return nullptr;
339 }
340
341 auto pandaFileVersion = pf->GetHeader()->version;
342 uint8_t *fileVersion = pandaFileVersion.data();
343
344 file->version = new uint8_t[ABCKIT_VERSION_SIZE];
345 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
346 std::copy(fileVersion, fileVersion + sizeof(uint8_t) * ABCKIT_VERSION_SIZE, file->version);
347
348 file->internal = new CtxIInternal {abc2program};
349 return file;
350 }
351
CloseFileStatic(AbckitFile * file)352 void CloseFileStatic(AbckitFile *file)
353 {
354 LIBABCKIT_LOG_FUNC;
355
356 auto *ctxIInternal = reinterpret_cast<struct CtxIInternal *>(file->internal);
357 delete ctxIInternal->driver;
358 delete ctxIInternal;
359 delete[] file->version;
360 delete file;
361 }
362
WriteAbcStatic(AbckitFile * file,const char * path,size_t len)363 void WriteAbcStatic(AbckitFile *file, const char *path, size_t len)
364 {
365 LIBABCKIT_LOG_FUNC;
366 auto spath = std::string(path, len);
367 LIBABCKIT_LOG(DEBUG) << spath << '\n';
368
369 auto program = file->GetStaticProgram();
370
371 auto emitDebugInfo = false;
372 std::map<std::string, size_t> *statp = nullptr;
373 ark::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = nullptr;
374
375 if (!pandasm::AsmEmitter::Emit(spath, *program, statp, mapsp, emitDebugInfo)) {
376 LIBABCKIT_LOG(DEBUG) << "FAILURE: " << pandasm::AsmEmitter::GetLastError() << '\n';
377 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
378 return;
379 }
380
381 LIBABCKIT_LOG(DEBUG) << "SUCCESS\n";
382 }
383
DestroyGraphStatic(AbckitGraph * graph)384 void DestroyGraphStatic(AbckitGraph *graph)
385 {
386 LIBABCKIT_LOG_FUNC;
387 auto *ctxGInternal = reinterpret_cast<CtxGInternal *>(graph->internal);
388 // dirty hack to obtain PandaFile pointer
389 // NOTE(mshimenkov): refactor it
390 auto *fileWrapper =
391 reinterpret_cast<panda_file::File *>(ctxGInternal->runtimeAdapter->GetBinaryFileForMethod(nullptr));
392 delete fileWrapper;
393 delete ctxGInternal->runtimeAdapter;
394 delete ctxGInternal->irInterface;
395 delete ctxGInternal->localAllocator;
396 delete ctxGInternal->allocator;
397 delete ctxGInternal;
398 delete graph;
399 }
400
401 } // namespace libabckit
402