• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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