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 "api_modifier.h"
17 #include "helpers/visit_helper/visit_helper-inl.h"
18 #include "libabckit/include/c/metadata_core.h"
19
20 #include <iostream>
21 #include <cstring>
22
Run()23 void ApiModifier::Run()
24 {
25 visitor_.EnumerateModules([&](AbckitCoreModule *mod) {
26 AbckitCoreImportDescriptor *impDescriptor = GetImportDescriptor(mod);
27 if (impDescriptor == nullptr) {
28 return;
29 }
30 visitor_.EnumerateModuleFunctions(mod, [&](AbckitCoreFunction *method) {
31 ModifyFunction(method, impDescriptor);
32 return true;
33 });
34 });
35 }
36
GetImportDescriptor(AbckitCoreModule * module)37 AbckitCoreImportDescriptor *ApiModifier::GetImportDescriptor(AbckitCoreModule *module)
38 {
39 AbckitCoreImportDescriptor *impDescriptor = nullptr;
40 visitor_.EnumerateModuleImports(module, [&](AbckitCoreImportDescriptor *id) {
41 auto importName = visitor_.GetString(implI_->importDescriptorGetName(id));
42 auto *importedModule = implI_->importDescriptorGetImportedModule(id);
43 auto source = visitor_.GetString(implI_->moduleGetName(importedModule));
44 if (source != methodInfo_.path) {
45 return false;
46 }
47 if (importName == methodInfo_.className) {
48 impDescriptor = id;
49 return true;
50 }
51 return false;
52 });
53 return impDescriptor;
54 }
55
ModifyFunction(AbckitCoreFunction * method,AbckitCoreImportDescriptor * id)56 void ApiModifier::ModifyFunction(AbckitCoreFunction *method, AbckitCoreImportDescriptor *id)
57 {
58 visitor_.EnumerateFunctionInsts(method, [&](AbckitInst *inst) {
59 auto subclassMethod = GetSubclassMethod(id, inst);
60 if (subclassMethod != nullptr) {
61 AddParamChecker(subclassMethod);
62 }
63 });
64 }
65
GetSubclassMethod(AbckitCoreImportDescriptor * id,AbckitInst * inst)66 AbckitCoreFunction *ApiModifier::GetSubclassMethod(AbckitCoreImportDescriptor *id, AbckitInst *inst)
67 {
68 if (dynG_->iGetOpcode(inst) != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR) {
69 return nullptr;
70 }
71
72 if (dynG_->iGetImportDescriptor(inst) != id) {
73 return nullptr;
74 }
75
76 AbckitCoreFunction *foundMethod = nullptr;
77 visitor_.EnumerateInstUsers(inst, [&](AbckitInst *user) {
78 if (dynG_->iGetOpcode(user) == ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINECLASSWITHBUFFER) {
79 auto method = implG_->iGetFunction(user);
80 auto klass = implI_->functionGetParentClass(method);
81 foundMethod = GetMethodToModify(klass);
82 }
83 });
84
85 return foundMethod;
86 }
87
GetMethodToModify(AbckitCoreClass * klass)88 AbckitCoreFunction *ApiModifier::GetMethodToModify(AbckitCoreClass *klass)
89 {
90 AbckitCoreFunction *foundMethod = nullptr;
91 visitor_.EnumerateClassMethods(klass, [&](AbckitCoreFunction *method) {
92 auto name = visitor_.GetString(implI_->functionGetName(method));
93 if (name == methodInfo_.methodName) {
94 foundMethod = method;
95 return true;
96 }
97 return false;
98 });
99 return foundMethod;
100 }
101
AddParamChecker(AbckitCoreFunction * method)102 void ApiModifier::AddParamChecker(AbckitCoreFunction *method)
103 {
104 AbckitGraph *graph = implI_->createGraphFromFunction(method);
105
106 visitor_.TransformMethod(method, [&](AbckitFile *file, AbckitCoreFunction *method) {
107 AbckitBasicBlock *startBB = implG_->gGetStartBasicBlock(graph);
108 AbckitInst *idx = implG_->bbGetLastInst(startBB);
109 AbckitInst *arr = implG_->iGetPrev(idx);
110
111 std::vector<AbckitBasicBlock *> succBBs;
112 implG_->bbVisitSuccBlocks(startBB, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
113 auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
114 succs->emplace_back(succBasicBlock);
115 return true;
116 });
117
118 AbckitString *str = implM_->createString(file, "length", strlen("length"));
119
120 AbckitInst *constant = implG_->gFindOrCreateConstantI32(graph, -1);
121 AbckitInst *arrLength = dynG_->iCreateLdobjbyname(graph, arr, str);
122
123 AbckitBasicBlock *trueBB = succBBs[0];
124 implG_->bbDisconnectSuccBlock(startBB, ABCKIT_TRUE_SUCC_IDX);
125 AbckitBasicBlock *falseBB = implG_->bbCreateEmpty(graph);
126 implG_->bbAppendSuccBlock(falseBB, implG_->gGetEndBasicBlock(graph));
127 implG_->bbAddInstBack(falseBB, dynG_->iCreateReturn(graph, constant));
128 AbckitBasicBlock *ifBB = implG_->bbCreateEmpty(graph);
129 AbckitInst *intrinsicGreatereq = dynG_->iCreateGreatereq(graph, arrLength, idx);
130 AbckitInst *ifInst = dynG_->iCreateIf(graph, intrinsicGreatereq, ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_EQ);
131 implG_->bbAddInstBack(ifBB, arrLength);
132 implG_->bbAddInstBack(ifBB, intrinsicGreatereq);
133 implG_->bbAddInstBack(ifBB, ifInst);
134 implG_->bbAppendSuccBlock(startBB, ifBB);
135 implG_->bbAppendSuccBlock(ifBB, trueBB);
136 implG_->bbAppendSuccBlock(ifBB, falseBB);
137
138 implM_->functionSetGraph(method, graph);
139 impl_->destroyGraph(graph);
140 });
141 }
142