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