• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 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     ASSERT(file->nameToFunction.count(name) == 0);
128     file->nameToFunction.insert({name, function.get()});
129 
130     for (auto &annoImpl : functionImpl.metadata->GetAnnotations()) {
131         auto anno = std::make_unique<AbckitCoreAnnotation>();
132         anno->impl = std::make_unique<AbckitArktsAnnotation>();
133         anno->GetArkTSImpl()->core = anno.get();
134 
135         for (auto &annoElemImpl : annoImpl.GetElements()) {
136             auto annoElem = std::make_unique<AbckitCoreAnnotationElement>();
137             annoElem->ann = anno.get();
138             auto annoElemImplName = annoElemImpl.GetName();
139             annoElem->name = CreateStringStatic(file, annoElemImplName.data(), annoElemImplName.size());
140             annoElem->impl = std::make_unique<AbckitArktsAnnotationElement>();
141             annoElem->GetArkTSImpl()->core = annoElem.get();
142             auto value = FindOrCreateValueStatic(file, *annoElemImpl.GetValue());
143             annoElem->value = value;
144 
145             anno->elements.emplace_back(std::move(annoElem));
146         }
147         function->annotations.emplace_back(std::move(anno));
148     }
149 
150     return function;
151 }
152 
CreateModule(AbckitFile * file,std::unordered_set<std::string> & globalClassNames,std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,const std::string & recordName)153 static void CreateModule(AbckitFile *file, std::unordered_set<std::string> &globalClassNames,
154                          std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
155                          const std::string &recordName)
156 {
157     auto [moduleName, className] = ClassGetNames(recordName);
158     if (globalClassNames.find(className) != globalClassNames.end()) {
159         if (nameToModule.find(moduleName) != nameToModule.end()) {
160             LIBABCKIT_LOG(FATAL) << "Duplicated ETSGLOBAL for module: " << moduleName << '\n';
161         }
162 
163         LIBABCKIT_LOG(DEBUG) << "Found module: '" << moduleName << "'\n";
164         auto m = std::make_unique<AbckitCoreModule>();
165         m->file = file;
166         m->target = ABCKIT_TARGET_ARK_TS_V2;
167         m->moduleName = CreateStringStatic(file, moduleName.data(), moduleName.size());
168         m->impl = std::make_unique<AbckitArktsModule>();
169         m->GetArkTSImpl()->core = m.get();
170         nameToModule.insert({moduleName, std::move(m)});
171     }
172 }
173 
CreateClass(std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,const std::string & moduleName,const std::string & className,ark::pandasm::Record & record)174 std::unique_ptr<AbckitCoreClass> CreateClass(
175     std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule, const std::string &moduleName,
176     const std::string &className, ark::pandasm::Record &record)
177 {
178     LIBABCKIT_LOG(DEBUG) << "  Found class. module: '" << moduleName << "' class: '" << className << "'\n";
179     ASSERT(nameToModule.find(moduleName) != nameToModule.end());
180     auto &classModule = nameToModule[moduleName];
181     auto abckitRecord = &record;
182     auto klass = std::make_unique<AbckitCoreClass>(classModule.get(), AbckitArktsClass(abckitRecord));
183     return klass;
184 }
185 
AssignClasses(std::unordered_map<std::string,std::unique_ptr<AbckitCoreModule>> & nameToModule,std::vector<std::unique_ptr<AbckitCoreClass>> & classes)186 static void AssignClasses(std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
187                           std::vector<std::unique_ptr<AbckitCoreClass>> &classes)
188 {
189     for (auto &klass : classes) {
190         auto fullName = klass->GetArkTSImpl()->impl.GetStaticClass()->name;
191         auto [moduleName, className] = ClassGetNames(fullName);
192         LIBABCKIT_LOG(DEBUG) << "moduleName, className, fullName: " << moduleName << ", " << className << ", "
193                              << fullName << '\n';
194         auto &classModule = nameToModule[moduleName];
195         classModule->InsertClass(className, std::move(klass));
196     }
197 }
198 
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)199 static void AssignFunctions(std::unordered_set<std::string> &globalClassNames,
200                             std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> &nameToModule,
201                             [[maybe_unused]] std::unordered_map<std::string, AbckitCoreClass *> &nameToClass,
202                             std::vector<std::unique_ptr<AbckitCoreFunction>> &functions)
203 {
204     for (auto &function : functions) {
205         std::string functionName = FunctionGetImpl(function.get())->name;
206         auto [moduleName, className] = FuncGetNames(functionName);
207         auto &functionModule = nameToModule[moduleName];
208         if (globalClassNames.find(className) != globalClassNames.end()) {
209             functionModule->functions.emplace_back(std::move(function));
210         } else {
211             ASSERT(functionModule->ct.find(className) != functionModule->ct.end());
212             auto &klass = functionModule->ct[className];
213             function->parentClass = klass.get();
214             klass->methods.emplace_back(std::move(function));
215         }
216     }
217 }
218 
219 static const std::string LAMBDA_RECORD_KEY = "LambdaObject";
220 static const std::string INIT_FUNC_NAME = "_$init$_";
221 static const std::string TRIGGER_CCTOR_FUNC_NAME = "_$trigger_cctor$_";
222 
ShouldCreateFuncWrapper(pandasm::Function & functionImpl,const std::string & className,const std::string & functionName)223 static bool ShouldCreateFuncWrapper(pandasm::Function &functionImpl, const std::string &className,
224                                     const std::string &functionName)
225 {
226     if (functionImpl.metadata->IsForeign() || (className.substr(0, LAMBDA_RECORD_KEY.size()) == LAMBDA_RECORD_KEY) ||
227         (functionName.find(INIT_FUNC_NAME, 0) != std::string::npos) ||
228         (functionName.find(TRIGGER_CCTOR_FUNC_NAME, 0) != std::string::npos)) {
229         // NOTE: find and fill AbckitCoreImportDescriptor
230         return false;
231     }
232 
233     if (IsAbstract(functionImpl.metadata.get())) {
234         // NOTE: ?
235         return false;
236     }
237 
238     return true;
239 }
240 
CreateWrappers(pandasm::Program * prog,AbckitFile * file)241 static void CreateWrappers(pandasm::Program *prog, AbckitFile *file)
242 {
243     std::unordered_set<std::string> globalClassNames = {"ETSGLOBAL", "_GLOBAL"};
244     file->program = prog;
245 
246     // Collect modules
247     std::unordered_map<std::string, std::unique_ptr<AbckitCoreModule>> nameToModule;
248     for (auto &[recordName, record] : prog->recordTable) {
249         if (record.metadata->IsForeign()) {
250             // NOTE: Create AbckitCoreImportDescriptor and AbckitCoreModuleDescriptor
251             continue;
252         }
253         CreateModule(file, globalClassNames, nameToModule, recordName);
254     }
255 
256     // Collect classes
257     std::vector<std::unique_ptr<AbckitCoreClass>> classes;
258     std::unordered_map<std::string, AbckitCoreClass *> nameToClass;
259     for (auto &[recordName, record] : prog->recordTable) {
260         if (record.metadata->IsForeign() || (recordName.find(LAMBDA_RECORD_KEY) != std::string::npos)) {
261             // NOTE: find and fill AbckitCoreImportDescriptor
262             continue;
263         }
264 
265         // NOTE: AbckitCoreAnnotationInterface
266 
267         auto [moduleName, className] = ClassGetNames(recordName);
268         if (globalClassNames.find(className) != globalClassNames.end()) {
269             continue;
270         }
271         classes.emplace_back(CreateClass(nameToModule, moduleName, className, record));
272         nameToClass[recordName] = classes.back().get();
273     }
274 
275     // Functions
276     std::vector<std::unique_ptr<AbckitCoreFunction>> functions;
277     std::unordered_map<std::string, AbckitCoreFunction *> nameToFunction;
278     for (auto &[functionName, functionImpl] : prog->functionTable) {
279         auto [moduleName, className] = FuncGetNames(functionName);
280 
281         if (ShouldCreateFuncWrapper(functionImpl, className, functionName)) {
282             functions.emplace_back(CollectFunction(file, nameToModule, functionName, functionImpl));
283             nameToFunction[functionName] = functions.back().get();
284         }
285     }
286 
287     AssignClasses(nameToModule, classes);
288     AssignFunctions(globalClassNames, nameToModule, nameToClass, functions);
289 
290     // NOTE: AbckitCoreExportDescriptor
291     // NOTE: AbckitModulePayload
292 
293     for (auto &[moduleName, module] : nameToModule) {
294         file->localModules.insert({moduleName, std::move(module)});
295     }
296 
297     DumpHierarchy(file);
298 
299     // Strings
300     for (auto &sImpl : prog->strings) {
301         auto s = std::make_unique<AbckitString>();
302         s->impl = sImpl;
303         file->strings.insert({sImpl, std::move(s)});
304     }
305 }
306 
307 struct CtxIInternal {
308     ark::abc2program::Abc2ProgramDriver *driver = nullptr;
309 };
310 
OpenAbcStatic(const char * path,size_t len)311 AbckitFile *OpenAbcStatic(const char *path, size_t len)
312 {
313     LIBABCKIT_LOG_FUNC;
314     auto spath = std::string(path, len);
315     LIBABCKIT_LOG(DEBUG) << spath << '\n';
316     auto *abc2program = new ark::abc2program::Abc2ProgramDriver();
317     if (!abc2program->Compile(spath)) {
318         LIBABCKIT_LOG(DEBUG) << "Failed to open " << spath << "\n";
319         delete abc2program;
320         return nullptr;
321     }
322     pandasm::Program &prog = abc2program->GetProgram();
323     auto file = new AbckitFile();
324     file->frontend = Mode::STATIC;
325     CreateWrappers(&prog, file);
326 
327     auto pf = panda_file::File::Open(spath);
328     if (pf == nullptr) {
329         LIBABCKIT_LOG(DEBUG) << "Failed to panda_file::File::Open\n";
330         delete abc2program;
331         delete file;
332         return nullptr;
333     }
334 
335     auto pandaFileVersion = pf->GetHeader()->version;
336     uint8_t *fileVersion = pandaFileVersion.data();
337 
338     file->version = new uint8_t[ABCKIT_VERSION_SIZE];
339     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
340     std::copy(fileVersion, fileVersion + sizeof(uint8_t) * ABCKIT_VERSION_SIZE, file->version);
341 
342     file->internal = new CtxIInternal {abc2program};
343     return file;
344 }
345 
CloseFileStatic(AbckitFile * file)346 void CloseFileStatic(AbckitFile *file)
347 {
348     LIBABCKIT_LOG_FUNC;
349 
350     auto *ctxIInternal = reinterpret_cast<struct CtxIInternal *>(file->internal);
351     delete ctxIInternal->driver;
352     delete ctxIInternal;
353     delete[] file->version;
354     delete file;
355 }
356 
WriteAbcStatic(AbckitFile * file,const char * path,size_t len)357 void WriteAbcStatic(AbckitFile *file, const char *path, size_t len)
358 {
359     LIBABCKIT_LOG_FUNC;
360     auto spath = std::string(path, len);
361     LIBABCKIT_LOG(DEBUG) << spath << '\n';
362 
363     auto program = file->GetStaticProgram();
364 
365     auto emitDebugInfo = false;
366     std::map<std::string, size_t> *statp = nullptr;
367     ark::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = nullptr;
368 
369     if (!pandasm::AsmEmitter::Emit(spath, *program, statp, mapsp, emitDebugInfo)) {
370         LIBABCKIT_LOG(DEBUG) << "FAILURE: " << pandasm::AsmEmitter::GetLastError() << '\n';
371         statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
372         return;
373     }
374 
375     LIBABCKIT_LOG(DEBUG) << "SUCCESS\n";
376 }
377 
DestroyGraphStatic(AbckitGraph * graph)378 void DestroyGraphStatic(AbckitGraph *graph)
379 {
380     LIBABCKIT_LOG_FUNC;
381     auto *ctxGInternal = reinterpret_cast<CtxGInternal *>(graph->internal);
382     // dirty hack to obtain PandaFile pointer
383     // NOTE(mshimenkov): refactor it
384     auto *fileWrapper =
385         reinterpret_cast<panda_file::File *>(ctxGInternal->runtimeAdapter->GetBinaryFileForMethod(nullptr));
386     delete fileWrapper;
387     delete ctxGInternal->runtimeAdapter;
388     delete ctxGInternal->irInterface;
389     delete ctxGInternal->localAllocator;
390     delete ctxGInternal->allocator;
391     delete ctxGInternal;
392     delete graph;
393 }
394 
395 }  // namespace libabckit
396