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 Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; 17import { Local } from '../base/Local'; 18import { ArkInstanceFieldRef, ArkStaticFieldRef } from '../base/Ref'; 19import { ArkAssignStmt } from '../base/Stmt'; 20import { ClassType } from '../base/Type'; 21import { Value } from '../base/Value'; 22import { BasicBlock } from '../graph/BasicBlock'; 23import { ArkClass } from '../model/ArkClass'; 24import { ArkFile } from '../model/ArkFile'; 25import { ArkMethod } from '../model/ArkMethod'; 26import { ArkNamespace } from '../model/ArkNamespace'; 27 28const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'VisibleValue'); 29 30export class VisibleValue { 31 private scopeChain: Scope[]; // 不包含currScope 32 private currScope: Scope; 33 private currVisibleValues: Value[]; 34 35 constructor() { 36 // TODO:填充全局变量 37 this.currScope = new Scope([], 0); 38 this.scopeChain = [this.currScope]; 39 this.currVisibleValues = [...this.currScope.values]; 40 } 41 42 /** get values that is visible in curr scope */ 43 public getCurrVisibleValues(): Value[] { 44 return this.currVisibleValues; 45 } 46 47 public getScopeChain(): Scope[] { 48 return this.scopeChain; 49 } 50 51 /** udpate visible values after entered a scope, only support step by step */ 52 public updateIntoScope(model: ArkModel): void { 53 let name = ''; 54 if (model instanceof BasicBlock) { 55 name = 'block: ' + model.toString(); 56 } else { 57 name = model.getName(); 58 } 59 logger.info('---- into scope:{', name, '}'); 60 61 // get values in this scope 62 let values: Value[] = []; 63 if (model instanceof ArkFile || model instanceof ArkNamespace) { 64 values = this.getVisibleValuesIntoFileOrNameSpace(model); 65 } else if (model instanceof ArkClass) { 66 values = this.getVisibleValuesIntoClass(model); 67 } else if (model instanceof ArkMethod) { 68 values = this.getVisibleValuesIntoMethod(model); 69 } else if (model instanceof BasicBlock) { 70 values = this.getVisibleValuesIntoBasicBlock(model); 71 } 72 73 // handle scope chain 74 const targetDepth = this.getTargetDepth(model); 75 this.addScope(values, targetDepth, model); 76 } 77 78 /** udpate visible values after left a scope, only support step by step */ 79 public updateOutScope(): void { 80 const currModel = this.currScope.arkModel as ArkModel; 81 82 let name = ''; 83 if (currModel instanceof BasicBlock) { 84 name = 'block: ' + currModel.toString(); 85 } else { 86 name = currModel.getName(); 87 } 88 logger.info('---- out scope:{', name, '}'); 89 90 let targetDepth = this.currScope.depth; 91 if (currModel instanceof BasicBlock) { 92 const successorsCnt = currModel.getSuccessors().length; 93 // if successorsCnt <= 0, unchange 94 if (successorsCnt > 1) { 95 targetDepth += 1; // goto inner scope 96 } 97 } 98 this.deleteScope(targetDepth); 99 } 100 101 /** clear up previous scope */ 102 private deleteScope(targetDepth: number): void { 103 const prevDepth = this.currScope.depth; 104 if (targetDepth > prevDepth) { 105 return; 106 } 107 108 let popScopeValuesCnt = 0; 109 let popScopeCnt = 0; 110 for (let i = this.scopeChain.length - 1; i >= 0; i--) { 111 if (this.scopeChain[i].depth < targetDepth) { 112 break; 113 } 114 popScopeCnt += 1; 115 popScopeValuesCnt += this.scopeChain[i].values.length; 116 } 117 118 this.scopeChain.splice(this.scopeChain.length - popScopeCnt, popScopeCnt)[0]; // popScopeCnt >= 1 119 this.currScope = this.scopeChain[this.scopeChain.length - 1]; 120 const totalValuesCnt = this.currVisibleValues.length; 121 this.currVisibleValues.splice(totalValuesCnt - popScopeValuesCnt, popScopeValuesCnt); 122 } 123 124 /** add this scope to scope chain and update visible values */ 125 private addScope(values: Value[], targetDepth: number, model: ArkModel): void { 126 const newScope = new Scope(values, targetDepth, model); 127 this.currScope = newScope; 128 this.scopeChain.push(this.currScope); 129 this.currVisibleValues.push(...this.currScope.values); 130 } 131 132 // TODO:构造嵌套关系树 133 private getTargetDepth(model: ArkModel): number { 134 const prevDepth = this.currScope.depth; 135 const prevModel = this.currScope.arkModel; 136 let targetDepth = prevDepth + 1; 137 if (model instanceof BasicBlock) { 138 const predecessorsCnt = model.getPredecessors().length; 139 if (predecessorsCnt <= 1) { 140 targetDepth = prevDepth + 1; 141 } else { 142 targetDepth = prevDepth; 143 } 144 } else if (model instanceof ArkFile && prevModel instanceof ArkFile) { 145 targetDepth = prevDepth; 146 } else if (model instanceof ArkNamespace && prevModel instanceof ArkNamespace) { 147 targetDepth = prevDepth; 148 } else if (model instanceof ArkClass && prevModel instanceof ArkClass) { 149 targetDepth = prevDepth; 150 } else if (model instanceof ArkMethod && prevModel instanceof ArkMethod) { 151 targetDepth = prevDepth; 152 } 153 return targetDepth; 154 } 155 156 private getVisibleValuesIntoFileOrNameSpace(fileOrNameSpace: ArkFile | ArkNamespace): Value[] { 157 let values: Value[] = []; 158 return values; 159 } 160 161 private getVisibleValuesIntoClass(cls: ArkClass): Value[] { 162 const values: Value[] = []; 163 const fields = cls.getFields(); 164 const classSignature = cls.getSignature(); 165 for (const field of fields) { 166 if (field.isStatic()) { 167 const staticFieldRef = new ArkStaticFieldRef(field.getSignature()); 168 values.push(staticFieldRef); 169 } else { 170 const instanceFieldRef = new ArkInstanceFieldRef(new Local('this', new ClassType(classSignature)), field.getSignature()); 171 values.push(instanceFieldRef); 172 } 173 } 174 return values; 175 } 176 177 private getVisibleValuesIntoMethod(method: ArkMethod): Value[] { 178 let visibleValues: Value[] = []; 179 return visibleValues; 180 } 181 182 private getVisibleValuesIntoBasicBlock(basiceBlock: BasicBlock): Value[] { 183 const visibleValues: Value[] = []; 184 for (const stmt of basiceBlock.getStmts()) { 185 if (stmt instanceof ArkAssignStmt) { 186 visibleValues.push(stmt.getLeftOp()); 187 } 188 } 189 return visibleValues; 190 } 191} 192 193type ArkModel = ArkFile | ArkNamespace | ArkClass | ArkMethod | BasicBlock; 194 195export class Scope { 196 public values: Value[]; 197 public depth: number; 198 public arkModel: ArkModel | null; 199 constructor(values: Value[], depth: number = -1, arkModel: ArkModel | null = null) { 200 this.values = values; 201 this.depth = depth; 202 this.arkModel = arkModel; 203 } 204} 205