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 16import { ArkAssignStmt, Stmt } from '../../core/base/Stmt'; 17import { UnknownType } from '../../core/base/Type'; 18import { CallGraphNode, CallGraphNodeKind } from '../model/CallGraph'; 19import { PointerAnalysis } from '../pointerAnalysis/PointerAnalysis'; 20import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; 21 22const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'PTA'); 23 24abstract class StatTraits { 25 TotalTime: number = 0; 26 startTime: number = 0; 27 endTime: number = 0; 28 29 public getStat(): string { 30 return ''; 31 } 32 33 public printStat(): void { 34 logger.trace(this.getStat()); 35 } 36} 37 38export class PTAStat extends StatTraits { 39 pta: PointerAnalysis; 40 numProcessedAddr: number = 0; 41 numProcessedCopy: number = 0; 42 numProcessedLoad: number = 0; 43 numProcessedWrite: number = 0; 44 numProcessedThis: number = 0; 45 numRealWrite: number = 0; 46 numRealLoad: number = 0; 47 48 numUnhandledFun: number = 0; 49 numTotalValuesInHandedFun: number = 0; 50 numTotalHandledValue: number = 0; 51 52 // Original type is UnknownType but inferred by PTA 53 numInferedUnknownValue: number = 0; 54 // Original type is not UnknownType and inferred with different type by PTA 55 numInferedDiffTypeValue: number = 0; 56 // Total number of values in the functions visited by PTA 57 totalValuesInVisitedFunc: number = 0; 58 // Original type is UnkonwnType and not inferred by PTA as well 59 numNotInferedUnknownValue: number = 0; 60 numUnhandledFunc: number = 0; 61 62 iterTimes: number = 0; 63 64 startMemUsage: any; 65 endMemUsage: any; 66 rssUsed: number = 0; 67 heapUsed: number = 0; 68 69 constructor(pta: PointerAnalysis) { 70 super(); 71 this.pta = pta; 72 } 73 74 public startStat(): void { 75 this.startTime = this.getNow(); 76 this.startMemUsage = process.memoryUsage(); 77 } 78 79 public endStat(): void { 80 this.endTime = this.getNow(); 81 this.endMemUsage = process.memoryUsage(); 82 this.TotalTime = (this.endTime - this.startTime) / 1000; 83 this.rssUsed = Number(this.endMemUsage.rss - this.startMemUsage.rss) / Number(1024 * 1024); 84 this.heapUsed = Number(this.endMemUsage.heapTotal - this.startMemUsage.heapTotal) / Number(1024 * 1024); 85 this.getInferedStat(); 86 this.getUnhandledFuncStat(); 87 } 88 89 public getNow(): number { 90 return new Date().getTime(); 91 } 92 93 private getInferedStat(): void { 94 let stmtStat = (s: Stmt): void => { 95 if (!(s instanceof ArkAssignStmt)) { 96 return; 97 } 98 99 let lop = s.getLeftOp(); 100 if (visited.has(lop)) { 101 return; 102 } 103 visited.add(lop); 104 105 if (inferred.includes(lop)) { 106 if (lop.getType() instanceof UnknownType) { 107 this.numInferedUnknownValue++; 108 } else { 109 this.numInferedDiffTypeValue++; 110 } 111 } else { 112 if (lop.getType() instanceof UnknownType) { 113 this.numNotInferedUnknownValue++; 114 } 115 } 116 this.totalValuesInVisitedFunc++; 117 }; 118 119 let inferred = Array.from(this.pta.getTypeDiffMap().keys()); 120 let visited = new Set(); 121 122 let cg = this.pta.getCallGraph(); 123 this.pta.getHandledFuncs().forEach(funcID => { 124 let f = cg.getArkMethodByFuncID(funcID); 125 f 126 ?.getCfg() 127 ?.getStmts() 128 .forEach(s => stmtStat(s)); 129 }); 130 } 131 132 private getUnhandledFuncStat(): void { 133 let cg = this.pta.getCallGraph(); 134 this.pta.getUnhandledFuncs().forEach(funcID => { 135 let cgNode = cg.getNode(funcID); 136 if ((cgNode as CallGraphNode).isSdkMethod()) { 137 return; 138 } 139 140 let f = cg.getArkMethodByFuncID(funcID); 141 if (f) { 142 this.numUnhandledFun++; 143 } 144 }); 145 } 146 147 public getStat(): string { 148 // TODO: get PAG stat and CG stat 149 let output: string; 150 output = '==== Pointer analysis Statictics: ====\n'; 151 output = output + `Processed address\t${this.numProcessedAddr}\n`; 152 output = output + `Processed copy\t\t${this.numProcessedCopy}\n`; 153 output = output + `Processed load\t\t${this.numProcessedLoad}\n`; 154 output = output + `Processed write\t\t${this.numProcessedWrite}\n`; 155 output = output + `Real write\t\t${this.numRealWrite}\n`; 156 output = output + `Real load\t\t${this.numRealLoad}\n`; 157 output = output + `Processed This\t\t${this.numProcessedThis}\n\n`; 158 output = output + `Unhandled function\t${this.numUnhandledFun}\n`; 159 output = output + `Total values in visited function\t${this.totalValuesInVisitedFunc}\n`; 160 output = output + `Infered Value unknown+different type\t${this.numInferedUnknownValue}+${this.numInferedDiffTypeValue}\n\n`; 161 output = output + `Total Time\t\t${this.TotalTime} S\n`; 162 output = output + `Total iterator Times\t${this.iterTimes}\n`; 163 output = output + `RSS used\t\t${this.rssUsed.toFixed(3)} Mb\n`; 164 output = output + `Heap used\t\t${this.heapUsed.toFixed(3)} Mb\n`; 165 return output; 166 } 167 168 public printStat(): void { 169 logger.trace(this.getStat()); 170 } 171} 172 173export class PAGStat extends StatTraits { 174 numDynamicCall: number = 0; 175 numTotalFunction: number = 0; 176 numTotalNode: number = 0; 177 178 public getStat(): string { 179 let output: string; 180 output = '==== PAG Statictics: ====\n'; 181 output = output + `Dynamic call\t\t${this.numDynamicCall}\n`; 182 output = output + `Total function handled\t${this.numTotalFunction}\n`; 183 output = output + `Total PAG Nodes\t\t${this.numTotalNode}\n`; 184 return output; 185 } 186 187 public printStat(): void { 188 logger.trace(this.getStat()); 189 } 190} 191 192export class CGStat extends StatTraits { 193 //real, vitual, intrinsic, constructor 194 numTotalNode: number = 0; 195 numReal: number = 0; 196 numVirtual: number = 0; 197 numIntrinsic: number = 0; 198 numConstructor: number = 0; 199 numBlank: number = 0; 200 201 public startStat(): void { 202 this.startTime = new Date().getTime(); 203 } 204 205 public endStat(): void { 206 this.endTime = new Date().getTime(); 207 this.TotalTime = (this.endTime - this.startTime) / 1000; 208 } 209 210 public addNodeStat(kind: CallGraphNodeKind): void { 211 switch (kind) { 212 case CallGraphNodeKind.real: 213 this.numReal++; 214 break; 215 case CallGraphNodeKind.vitual: 216 this.numVirtual++; 217 break; 218 case CallGraphNodeKind.constructor: 219 this.numConstructor++; 220 break; 221 case CallGraphNodeKind.intrinsic: 222 this.numIntrinsic++; 223 break; 224 default: 225 this.numBlank++; 226 } 227 this.numTotalNode++; 228 } 229 230 public getStat(): string { 231 let output: string; 232 output = '==== CG Statictics: ====\n'; 233 output = output + `CG construction Total Time\t\t${this.TotalTime} S\n`; 234 output = output + `Real function\t\t${this.numReal}\n`; 235 output = output + `Intrinsic function\t${this.numIntrinsic}\n`; 236 output = output + `Constructor function\t${this.numConstructor}\n`; 237 output = output + `Virtual function\t\t${this.numVirtual}\n`; 238 output = output + `Blank function\t\t${this.numBlank}\n`; 239 output = output + `Total\t\t\t${this.numTotalNode}\n`; 240 return output; 241 } 242} 243