1### The main goals of this cookbook are to provide recipes for the main supported functions and to help you quickly get started with the LibAbcKit API. 2 3## Get API implementations 4 5```cpp 6enum AbckitApiVersion version = ABCKIT_VERSION_RELEASE_1_0_0; 7auto impl = AbckitGetApiImpl(version); // top level api with entry points 8auto implI = AbckitGetInspectApiImpl(version); // language-independent inspect api 9auto implM = AbckitGetModifyApiImpl(version); // language-independent modify api 10auto implArkI = AbckitGetArkTSInspectApiImpl(version); // language-dependent inspect api 11auto implArkM = AbckitGetArkTSModifyApiImpl(version); // language-dependent modify api 12 13auto implG = AbckitGetGraphApiImpl(version); // language-independent graph api 14auto dynG = AbckitGetIsaApiDynamicImpl(version); // language-dependent graph api 15auto statG = AbckitGetIsaApiStaticImpl(version); // language-dependent graph api 16``` 17 18One static instance of each at the beginning of the .cpp file is enough 19 20## Errors 21 22Every API in libabckit sets error value after execution. You can get it with `impl->getLastError()`. If there are no errors, the return value will be ABCKIT_STATUSNO_ERROR. 23Сheck the execution status with: 24 25```cpp 26assert(impl->getLastError() == ABCKIT_STATUSNO_ERROR); 27``` 28 29## Strings in LibAbcKit 30 31Here is an useful example of a custom function for working with strings in libabckit: 32 33```cpp 34AbckitString *str = implI->createString(file, "new_string"); 35 36std::string AbckitStringToString(AbckitFile *file, AbckitString *str) 37{ 38 std::size_t len = 0; 39 implI->abckitStringToString(file, str, nullptr, &len); 40 auto name = malloc(len + 1); 41 implI->abckitStringToString(file, str, name, &len); 42 std::string res {name}; 43 free(name); 44 45 return res; 46} 47``` 48 49# Metadata 50 51## Open/Close/Write 52 53### _Open file_ 54 55Mandatory and only entry point 56 57```cpp 58AbckitFile *file = implI->openAbc(path_to_abc); 59``` 60 61Make sure that you have used the WriteAbc() or CloseFile() function after working with the file. This way you will avoid memory leaks 62 63### _Write or Close_ 64 65```cpp 66impl->writeAbc(file, path_to_output_file); // save changes and close 67// or 68impl->closeFile(file); // close without saving changes 69``` 70 71## Traversing 72 73libabckit objects hierarchy: 74 751. file contains modules ("file" is ".abc file" and "module" is the abstract of "source code file") 762. module contains: namespaces, top level classes, top level functions 773. namespace contains: nested namespaces, classes, functions 784. class contains: functions (methods) 795. functions contains: nested functions 80 81<!-- file module class function -> introduce hierarchy --> 82 83All the enumerators in libabckit accepts libabckit object, void\* data with user data and callback lambda: 84 85```cpp 86void XXXEnumerateYYY(AbckitCoreXXX* xxx, void *data, bool(*cb)(AbckitCoreYYY* yyy, void *data)) 87``` 88 89### _Enumerate methods from class_ 90 91```cpp 92// AbckitCoreClass *klass 93implI->classEnumerateMethods(klass, data, [](AbckitCoreMethod *method, void *data) { 94 return true; 95}); 96``` 97 98### _Collect all top level classes from module_ 99 100```cpp 101// AbckitCoreModule *module 102std::vector<AbckitCoreClass *> classes; 103implI->moduleEnumerateClasses(module, (void*)&classes, [](AbckitCoreClass *klass, void *data) { 104 ((std::vector<AbckitCoreClass*>*)data)->emplace.back(klass); 105 return true; 106}); 107``` 108 109## Inspecting 110 111### _Get method's parent class_ 112 113```cpp 114// AbckitCoreMethod *method 115AbckitCoreClass *klass = implI->functionGetParentClass(method); 116``` 117 118### _Get value_ 119 120<!-- Test: LiteralGetU32_2 --> 121 122```cpp 123// AbckitLiteral *res 124void GetValues(AbckitValue *u32_res, AbckitValue *double_res, AbckitValue *string_res) { 125 uint32_t val = implI->literalGetU32(u32_res); 126 double d = implI->valueGetDouble(double_res); 127 AbckitString *s = implI->valueGetString(string_res); 128} 129``` 130 131### _Get module name_ 132 133```cpp 134// AbckitCoreModule *mod 135AbckitString *GetModuleName(AbckitCoreModule *mod) { 136 return implI->moduleGetName(mod); 137} 138``` 139 140## Metadata Lang API 141 142### _Add annotation for arkts method_ 143 144```cpp 145void AddAnno(AbckitModifyContext *file, AbckitCoreMethod *method) { 146 auto mod = implI->functionGetModule(method); 147 148 // Find annoation interface with name "Anno" 149 AbckitCoreAnnotationInterface *ai; 150 implI->moduleEnumerateAnnotationInterfaces(mod, &ai, [](AbckitCoreAnnotationInterface *annoI, void *data) { 151 auto ai1 = (AbckitCoreAnnotationInterface **)data; 152 auto file = implI->annotationInterfaceGetInspectContext(annoI); 153 auto str = implI->annotationInterfaceGetName(annoI); 154 auto name = AbckitStringToString(file, str); 155 if (name == "Anno") { 156 (*ai1) = annoI; 157 } 158 return true; 159 }); 160 161 // Add "@Anno" annotation for method 162 struct AbckitArktsAnnotationCreateParams annoCreateParams; 163 annoCreateParams.ai = implArkI->coreAnnotationInterfaceToArkTsAnnotationInterface(ai); 164 AbckitArktsAnnotation *anno = implArkM->functionAddAnnotation(file, 165 implArkI->coreFunctionToArkTsFunction(method), &annoCreateParams); 166} 167``` 168 169### _Cast AbckitArtksXXX -> AbckitXXX / AbckitXXX -> AbckitArktsXXX_ 170 171```cpp 172AbckitCoreModule *CastToAbcKit(AbckitArktsInspectApi implArkI, AbckitArktsModule *mod) { 173 return implArkI->arkTsModuleToCoreModule(mod); } 174 175AbckitArktsAnnotation *CastToArkTS(AbckitArktsInspectApi implArkI, AbckitCoreAnnotation *anno) { 176 return implArkI->coreAnnotationToArkTsAnnotation(anno); } 177``` 178 179## Modification 180 181### _Create values_ 182 183```cpp 184AbckitLiteral *res1 = implM->createLiteralString(file, "asdf"); 185AbckitLiteral *res2 = implM->createLiteralDouble(file, 1.0); 186AbckitLiteral *res = implM->createLiteralU32(file, 1); 187``` 188 189```cpp 190AbckitValue *res_u = implM->createValueU1(file, true); 191AbckitValue *res_d = implM->createValueDouble(file, 1.2); 192``` 193 194### _Get value type_ 195 196<!-- Test: ValueGetType_1 --> 197 198```cpp 199AbckitType *s_type = implI->valueGetType(res_s); // val_s->id == ABCKIT_TYPE_ID_STRING 200AbckitType *u_type = implI->valueGetType(res_u); // val_u->id == ABCKIT_TYPE_ID_U1 201AbckitType *d_type = implI->valueGetType(res_d); // val_d->id == ABCKIT_TYPE_ID_F32, 202``` 203 204# Graph 205 206## _Create and destroy graph_ 207 208```cpp 209AbckitGraph *graph = implI->createGraphFromFunction(method); 210// ... 211impl->destroyGraph(graph); 212``` 213 214## _Graph traversal_ 215 216```cpp 217implG->gVisitBlocksRpo(ctxG, &bbs, [](AbckitBasicBlock *bb, void *data) { 218 // user lambda 219}); 220``` 221 222```cpp 223implG->bbVisitSuccBlocks(bb, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) { 224 // user lambda 225}); 226``` 227 228```cpp 229implG->bbVisitPredBlocks(bb, &predBBs, 230 [](AbckitBasicBlock *succBasicBlock, void *d) { 231 // user lambda 232 }); 233 234// ... 235``` 236 237### _Collect all basic blocks from graph_ 238 239```cpp 240std::vector<AbckitBasicBlock *> bbs; 241implG->gVisitBlocksRPO(ctxG, &bbs, [](AbckitBasicBlock *bb, void *data) { 242 ((std::vector<AbckitBasicBlock *> *)data)->emplace_back(bb); 243}); 244``` 245 246### _Collect all inst in basic block_ 247 248```cpp 249std::vector<AbckitInst *> insts; 250for (auto *inst = implG->bbGetFirstInst(bb); inst != nullptr; inst = implG->iGetNext(inst)) { 251 insts.emplace_back(inst); 252} 253``` 254 255### _Collect block's succs_ 256 257```cpp 258std::vector<AbckitBasicBlock *> succBBs; 259implG->bbVisitSuccBlocks(bb, &succBBs, 260 [](AbckitBasicBlock *succBasicBlock, void *d) { 261 auto *succs = (std::vector<AbckitBasicBlock *> *)d; 262 succs->emplace_back(succBasicBlock); 263 }); 264``` 265 266## Graph inspecting 267 268### _Get method_ 269 270```cpp 271AbckitCoreMethod *method = implG->iGetFunction(curInst); 272``` 273 274## Graph modification 275 276### _Create basic block_ 277 278```cpp 279AbckitBasicBlock *empty = implG->bbCreateEmpty(ctxG); 280``` 281 282### _Create insts with const_ 283 284```cpp 285AbckitInst *new_inst = implG->gFindOrCreateConstantI64(ctxG, 1U); 286``` 287 288### _Connect and disconnect blocks_ 289 290<!-- Test: BBcreateEmptyBlock_1 --> 291 292```cpp 293auto *start = implG->gGetStartBasicBlock(ctxG); 294auto *bb = implG->bbCreateEmpty(ctxG); 295 296implG->bbInsertSuccBlock(start, bb, 0); 297implG->bbDisconnectSuccBlock(start, 0); 298``` 299 300### _Insert instructions_ 301 302```cpp 303implG->bbAddInstBack(bb, some_inst_1); 304implG->iInsertAfter(some_inst_1, some_inst_2); 305``` 306 307## Graph-lang 308 309### _Create instructions_ 310 311```cpp 312// for static 313AbckitInst *neg_inst = statG->iCreateNeg(ctxG, new_inst); 314AbckitInst *add_inst = statG->iCreateAdd(ctxG, neg_inst, new_inst); 315AbckitInst *ret = statG->iCreateReturnVoid(ctxG); 316 317// for dynamic 318AbckitInst *neg_inst = dynG->iCreateNeg(ctxG, new_inst); 319AbckitInst *add_inst = dynG->iCreateAdd2(ctxG, neg_inst, new_inst); 320AbckitInst *ret = dynG->iCreateReturnundefined(ctxG); 321``` 322 323### _Create 'print("Hello")' for ArkTS1.0_ 324 325```cpp 326AbckitInst *str = dynG->iCreateLoadString(ctxG, implM->createString(file, "Hello", strlen("Hello"))); 327AbckitInst *print = dynG->iCreateTryldglobalbyname(ctxG, implM->createString(file, "print", strlen("print"))); 328AbckitInst *callArg = dynG->iCreateCallarg1(ctxG, print, str); 329``` 330 331# User scenarios 332 333### _Enumerate the names of methods from the module_ 334 335```cpp 336std::vector<std::string> functionNames; 337 338std::function<void(AbckitCoreFunction *)> cbFunc = [&](AbckitCoreFunction *f) { 339 auto funcName = helpers::AbckitStringToString(implI->functionGetName(f)); 340 functionNames.emplace_back(funcName); 341}; 342 343std::function<void(AbckitCoreClass *)> cbClass = [&](AbckitCoreClass *c) { 344 implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) { 345 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m); 346 return true; 347 }); 348}; 349 350std::function<void(AbckitCoreNamespace *)> cbNamespace; 351cbNamespace = [&](AbckitCoreNamespace *n) { 352 implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) { 353 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n); 354 return true; 355 }); 356 implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) { 357 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c); 358 return true; 359 }); 360 implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) { 361 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(f); 362 return true; 363 }); 364}; 365 366std::function<void(AbckitCoreModule *)> cbModule = [&](AbckitCoreModule *m) { 367 implI->moduleEnumerateNamespaces(m, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) { 368 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n); 369 return true; 370 }); 371 implI->moduleEnumerateClasses(m, &cbClass, [](AbckitCoreClass *c, void *cb) { 372 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c); 373 return true; 374 }); 375 implI->moduleEnumerateTopLevelFunctions(m, &cbFunc, [](AbckitCoreFunction *m, void *cb) { 376 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m); 377 return true; 378 }); 379}; 380 381implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) { 382 (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m); 383 return true; 384}); 385``` 386 387### _Collect predecessor basic blocks_ 388 389```cpp 390std::vector<AbckitBasicBlock *> predBBs; 391implG->bbVisitPredBlocks(bb, &predBBs, 392 [](AbckitBasicBlock *succBasicBlock, void *d) { 393 auto *preds = (std::vector<AbckitBasicBlock *> *)d; 394 preds->emplace_back(succBasicBlock); 395 }); 396``` 397