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 { ArkBody } from '../ArkBody'; 17import { ArkMethod } from '../ArkMethod'; 18import { FieldSignature, MethodSignature, methodSignatureCompare, MethodSubSignature } from '../ArkSignature'; 19import { CfgBuilder } from '../../graph/builder/CfgBuilder'; 20import * as ts from 'ohos-typescript'; 21import { Local } from '../../base/Local'; 22import { MethodParameter } from './ArkMethodBuilder'; 23import { LEXICAL_ENV_NAME_PREFIX, NAME_DELIMITER, NAME_PREFIX } from '../../common/Const'; 24import { ArkParameterRef, ArkStaticFieldRef, ClosureFieldRef, GlobalRef } from '../../base/Ref'; 25import { ArkAliasTypeDefineStmt, ArkAssignStmt, ArkInvokeStmt, ArkReturnStmt } from '../../base/Stmt'; 26import { AliasType, ArrayType, ClosureType, FunctionType, LexicalEnvType, Type, UnclearReferenceType, UnionType } from '../../base/Type'; 27import { AbstractInvokeExpr, ArkPtrInvokeExpr } from '../../base/Expr'; 28 29type NestedMethodChain = { 30 parent: ArkMethod; 31 children: NestedMethodChain[] | null; 32}; 33 34export class BodyBuilder { 35 private cfgBuilder: CfgBuilder; 36 private globals?: Map<string, GlobalRef>; 37 38 constructor(methodSignature: MethodSignature, sourceAstNode: ts.Node, declaringMethod: ArkMethod, sourceFile: ts.SourceFile) { 39 this.cfgBuilder = new CfgBuilder(sourceAstNode, methodSignature.getMethodSubSignature().getMethodName(), declaringMethod, sourceFile); 40 } 41 42 public build(): ArkBody | null { 43 this.cfgBuilder.buildCfgBuilder(); 44 if (!this.cfgBuilder.isBodyEmpty()) { 45 const { cfg, locals, globals, aliasTypeMap, traps } = this.cfgBuilder.buildCfg(); 46 if (globals !== null) { 47 this.setGlobals(globals); 48 } 49 cfg.buildDefUseStmt(locals); 50 51 return new ArkBody(locals, cfg, aliasTypeMap, traps.length ? traps : undefined); 52 } 53 return null; 54 } 55 56 public getCfgBuilder(): CfgBuilder { 57 return this.cfgBuilder; 58 } 59 60 public getGlobals(): Map<string, GlobalRef> | undefined { 61 return this.globals; 62 } 63 64 public setGlobals(globals: Map<string, GlobalRef>): void { 65 this.globals = globals; 66 } 67 68 /** 69 * Find out all locals in the parent method which are used by the childrenChain, these locals are the closures of the root node of the childrenChain. 70 * childrenChain contains all nested method from the root node of the childrenChain. 71 * baseLocals are all locals defined in the outer function. 72 * allNestedLocals are collect all locals defined in all outer functions of this childrenChain. 73 * Only the globals of the root of the childrenChain, which are in the baseLocals but not in the allNestedLocals are the actual closures that in baseLocals. 74 */ 75 private findClosuresUsedInNested(childrenChain: NestedMethodChain, baseLocals: Map<string, Local>, allNestedLocals: Map<string, Local>): Local[] | null { 76 let closuresRes: Local[] = []; 77 78 const nestedMethod = childrenChain.parent; 79 let nestedGlobals = nestedMethod.getBodyBuilder()?.getGlobals(); 80 if (nestedGlobals !== undefined) { 81 for (let global of nestedGlobals.values()) { 82 const nestedLocal = allNestedLocals.get(global.getName()); 83 const closure = baseLocals.get(global.getName()); 84 if (nestedLocal === undefined && closure !== undefined) { 85 closuresRes.push(closure); 86 } 87 } 88 } 89 const children = childrenChain.children; 90 if (children === null) { 91 return closuresRes; 92 } 93 for (let chain of children) { 94 const nestedLocals = nestedMethod.getBody()?.getLocals(); 95 if (nestedLocals !== undefined) { 96 nestedLocals.forEach((value, key) => { 97 allNestedLocals.set(key, value); 98 }); 99 } 100 const closures = this.findClosuresUsedInNested(chain, baseLocals, allNestedLocals); 101 if (closures) { 102 closuresRes.push(...closures); 103 } 104 } 105 return closuresRes; 106 } 107 108 /** 109 * 1. Find out all locals in the parent method which are used by the childrenChain, these locals are the closures of the root node of the childrenChain. 110 * 2. Create a lexical env local in the parent method, and pass it to root node of the childrenChain through the method signature. 111 * 3. Update the root node of the childrenChain to add parameterRef assign stmt and closureRef assign stmt. 112 * 4. Recursively do this for all nested method level by level. 113 */ 114 private buildLexicalEnv(childrenChain: NestedMethodChain, baseLocals: Map<string, Local>, index: number): number { 115 let usedClosures = this.findClosuresUsedInNested(childrenChain, baseLocals, new Map<string, Local>()); 116 const nestedMethod = childrenChain.parent; 117 const nestedSignature = nestedMethod.getImplementationSignature(); 118 if (nestedSignature !== null && usedClosures !== null && usedClosures.length > 0) { 119 let lexicalEnv = new LexicalEnvType(nestedSignature, usedClosures); 120 const closuresLocal = new Local(`${LEXICAL_ENV_NAME_PREFIX}${index++}`, lexicalEnv); 121 baseLocals.set(closuresLocal.getName(), closuresLocal); 122 this.updateNestedMethodWithClosures(nestedMethod, closuresLocal); 123 } else if (usedClosures === null || usedClosures.length === 0) { 124 this.moveCurrentMethodLocalToGlobal(nestedMethod); 125 } 126 127 const nextNestedChains = childrenChain.children; 128 if (nextNestedChains === null) { 129 return index; 130 } 131 for (let nextChain of nextNestedChains) { 132 const newBaseLocals = nestedMethod.getBody()?.getLocals(); 133 if (newBaseLocals === undefined) { 134 return index; 135 } 136 index = this.buildLexicalEnv(nextChain, newBaseLocals, index); 137 } 138 return index; 139 } 140 141 /** 142 * Find out and tag all closures from globals, and remove closures from both globals and locals. 143 * Precondition: body build has been done. All locals, globals and closures are both set as Local in body, 144 * while potential globals and closures are also recorded in bodybuilder. 145 * Constraint: only the outermost function can call this method to recursively handle closures of itself as well as all nested methods. 146 */ 147 public handleGlobalAndClosure(): void { 148 /** 149 * Step1: Handle the outermost function, take it as Level 0. 150 * There must be no closures in Level 0. So only need to remove the locals which with the same name as the ones in globals. 151 */ 152 let outerMethod = this.getCfgBuilder().getDeclaringMethod(); 153 let outerGlobals = outerMethod.getBodyBuilder()?.getGlobals(); 154 outerMethod.freeBodyBuilder(); 155 let outerLocals = outerMethod.getBody()?.getLocals(); 156 if (outerGlobals !== undefined && outerLocals !== undefined) { 157 outerGlobals.forEach((value, key) => { 158 const local = outerLocals!.get(key); 159 if (local !== undefined) { 160 value.addUsedStmts(local.getUsedStmts()); 161 outerLocals!.delete(key); 162 } 163 }); 164 if (outerGlobals.size > 0) { 165 outerMethod.getBody()?.setUsedGlobals(outerGlobals); 166 } 167 } 168 169 let nestedMethodChains = this.generateNestedMethodChains(outerMethod).children; 170 if (nestedMethodChains === null || outerLocals === undefined) { 171 return; 172 } 173 let closuresIndex = 0; 174 for (let nestedChain of nestedMethodChains) { 175 /** 176 * Step2: Handle each nested function in Level 1 one by one. 177 * Find out all closures from Level 0 used by these Level 1 functions as well as all their children nested functions. 178 * This will be done level by level recursively. 179 */ 180 closuresIndex = this.buildLexicalEnv(nestedChain, outerLocals, closuresIndex); 181 182 /** 183 * Step3: Delete old globals which are recognized as closures, then the rest globals are the true globals. 184 * The redundancy locals should be deleted but the used stmts of them should be restored to globals. 185 * This will be done level by level recursively. 186 */ 187 this.reorganizeGlobalAndLocal(nestedChain); 188 189 /** 190 * Step4: Infer UnclearReferenceType to check whether it is the type alias define in its parent function.. 191 */ 192 this.inferTypesDefineInOuter(outerMethod, nestedChain); 193 194 /** 195 * Step5: For each nested function, find out whether it is called by its parent function and update the related locals, globals and stmts. 196 */ 197 this.updateNestedMethodUsedInOuter(nestedChain); 198 199 this.freeBodyBuilder(nestedChain); 200 } 201 } 202 203 private freeBodyBuilder(nestedChain: NestedMethodChain): void { 204 nestedChain.parent.freeBodyBuilder(); 205 const childrenChains = nestedChain.children; 206 if (childrenChains === null) { 207 return; 208 } 209 for (const chain of childrenChains) { 210 this.freeBodyBuilder(chain); 211 } 212 } 213 214 private updateLocalTypesWithTypeAlias(locals: Map<string, Local>, typeAliases: Map<string, [AliasType, ArkAliasTypeDefineStmt]>): void { 215 for (let local of locals.values()) { 216 const newType = this.inferUnclearReferenceTypeWithTypeAlias(local.getType(), typeAliases); 217 if (newType !== null) { 218 local.setType(newType); 219 } 220 } 221 } 222 223 private inferUnclearReferenceTypeWithTypeAlias(localType: Type, typeAliases: Map<string, [AliasType, ArkAliasTypeDefineStmt]>): Type | null { 224 if (localType instanceof ArrayType && localType.getBaseType() instanceof UnclearReferenceType) { 225 const typeAlias = typeAliases.get((localType.getBaseType() as UnclearReferenceType).getName()); 226 if (typeAlias !== undefined) { 227 localType.setBaseType(typeAlias[0]); 228 return localType; 229 } 230 return null; 231 } 232 if (localType instanceof UnionType) { 233 const optionTypes = localType.getTypes(); 234 for (let i = 0; i < optionTypes.length; i++) { 235 const newType = this.inferUnclearReferenceTypeWithTypeAlias(optionTypes[i], typeAliases); 236 if (newType !== null) { 237 optionTypes[i] = newType; 238 } 239 } 240 return localType; 241 } 242 if (localType instanceof UnclearReferenceType) { 243 const typeAlias = typeAliases.get(localType.getName()); 244 if (typeAlias !== undefined) { 245 return typeAlias[0]; 246 } 247 } 248 return null; 249 } 250 251 private generateNestedMethodChains(outerMethod: ArkMethod): NestedMethodChain { 252 let candidateMethods: ArkMethod[] = []; 253 outerMethod 254 .getDeclaringArkClass() 255 .getMethods() 256 .forEach(method => { 257 if (method.getName().startsWith(NAME_PREFIX) && method.getName().endsWith(`${NAME_DELIMITER}${outerMethod.getName()}`)) { 258 candidateMethods.push(method); 259 } 260 }); 261 const childrenChains = this.getNestedChildrenChains(outerMethod, candidateMethods); 262 if (childrenChains.length > 0) { 263 return { parent: outerMethod, children: childrenChains }; 264 } 265 return { parent: outerMethod, children: null }; 266 } 267 268 private getNestedChildrenChains(parentMethod: ArkMethod, candidateMethods: ArkMethod[]): NestedMethodChain[] { 269 let nestedMethodChain: NestedMethodChain[] = []; 270 for (let method of candidateMethods) { 271 const outerMethodSignature = method.getOuterMethod()?.getSignature(); 272 if (outerMethodSignature !== undefined && methodSignatureCompare(parentMethod.getSignature(), outerMethodSignature)) { 273 const childrenChains = this.getNestedChildrenChains(method, candidateMethods); 274 if (childrenChains.length > 0) { 275 nestedMethodChain.push({ parent: method, children: childrenChains }); 276 } else { 277 nestedMethodChain.push({ parent: method, children: null }); 278 } 279 } 280 } 281 return nestedMethodChain; 282 } 283 284 private moveCurrentMethodLocalToGlobal(method: ArkMethod): void { 285 const globals = method.getBodyBuilder()?.getGlobals(); 286 const locals = method.getBody()?.getLocals(); 287 if (locals === undefined || globals === undefined) { 288 return; 289 } 290 globals.forEach((value, key) => { 291 const local = locals.get(key); 292 if (local !== undefined) { 293 value.addUsedStmts(local.getUsedStmts()); 294 locals.delete(key); 295 } 296 }); 297 298 if (globals.size > 0) { 299 method.getBody()?.setUsedGlobals(globals); 300 } 301 } 302 303 private reorganizeGlobalAndLocal(nestedChain: NestedMethodChain): void { 304 const nestedMethod = nestedChain.parent; 305 const params = nestedMethod.getSubSignature().getParameters(); 306 const globals = nestedMethod.getBodyBuilder()?.getGlobals(); 307 if (params.length > 0 && params[0].getType() instanceof LexicalEnvType && globals !== undefined) { 308 const closures = (params[0].getType() as LexicalEnvType).getClosures(); 309 for (let closure of closures) { 310 globals.delete(closure.getName()); 311 } 312 } 313 314 this.moveCurrentMethodLocalToGlobal(nestedMethod); 315 316 const childrenChains = nestedChain.children; 317 if (childrenChains === null) { 318 return; 319 } 320 for (const chain of childrenChains) { 321 this.reorganizeGlobalAndLocal(chain); 322 } 323 } 324 325 // 对嵌套函数中的UnclearReferenceType类型的变量进行类型推导,类型是否为外层函数中定义的类型别名 326 private inferTypesDefineInOuter(outerMethod: ArkMethod, childrenChain: NestedMethodChain): void { 327 const typeAliases = outerMethod.getBody()?.getAliasTypeMap(); 328 const nestedLocals = childrenChain.parent.getBody()?.getLocals(); 329 if (typeAliases !== undefined && nestedLocals !== undefined) { 330 this.updateLocalTypesWithTypeAlias(nestedLocals, typeAliases); 331 } 332 const childrenChains = childrenChain.children; 333 if (childrenChains === null) { 334 return; 335 } 336 for (const chain of childrenChains) { 337 this.inferTypesDefineInOuter(childrenChain.parent, chain); 338 } 339 } 340 341 private updateNestedMethodUsedInOuter(nestedChain: NestedMethodChain): void { 342 const nestedMethod = nestedChain.parent; 343 const outerMethod = nestedMethod.getOuterMethod(); 344 if (outerMethod === undefined) { 345 return; 346 } 347 const outerLocals = outerMethod.getBody()?.getLocals(); 348 if (outerLocals !== undefined) { 349 for (let local of outerLocals.values()) { 350 if ( 351 local.getType() instanceof LexicalEnvType && 352 methodSignatureCompare((local.getType() as LexicalEnvType).getNestedMethod(), nestedMethod.getSignature()) 353 ) { 354 this.updateOuterMethodWithClosures(outerMethod, nestedMethod, local); 355 break; 356 } 357 } 358 } 359 360 const nestedMethodName = nestedMethod.getName(); 361 const originalMethodName = this.getOriginalNestedMethodName(nestedMethodName) ?? ''; 362 const outerGlobals = outerMethod.getBody()?.getUsedGlobals(); 363 const callGlobal = outerGlobals?.get(nestedMethodName) ?? outerGlobals?.get(originalMethodName); 364 if (callGlobal !== undefined && callGlobal instanceof GlobalRef && callGlobal.getRef() === null) { 365 const fieldSignature = new FieldSignature( 366 nestedMethodName, 367 nestedMethod.getDeclaringArkClass().getSignature(), 368 new FunctionType(nestedMethod.getSignature()) 369 ); 370 callGlobal.setRef(new ArkStaticFieldRef(fieldSignature)); 371 } 372 373 const childrenChains = nestedChain.children; 374 if (childrenChains === null) { 375 return; 376 } 377 for (const chain of childrenChains) { 378 this.updateNestedMethodUsedInOuter(chain); 379 } 380 } 381 382 private updateNestedMethodWithClosures(nestedMethod: ArkMethod, closuresLocal: Local): void { 383 if (!(closuresLocal.getType() instanceof LexicalEnvType)) { 384 return; 385 } 386 387 const declareSignatures = nestedMethod.getDeclareSignatures(); 388 declareSignatures?.forEach((signature, index) => { 389 nestedMethod.setDeclareSignatureWithIndex(this.createNewSignatureWithClosures(closuresLocal, signature), index); 390 }); 391 392 const implementSignature = nestedMethod.getImplementationSignature(); 393 if (implementSignature !== null) { 394 nestedMethod.setImplementationSignature(this.createNewSignatureWithClosures(closuresLocal, implementSignature)); 395 } 396 397 this.addClosureParamsAssignStmts(closuresLocal, nestedMethod); 398 } 399 400 private updateOuterMethodWithClosures(outerMethod: ArkMethod, nestedMethod: ArkMethod, closuresLocal: Local): void { 401 const nestedMethodName = nestedMethod.getName(); 402 const nestedMethodLocal = outerMethod.getBody()?.getLocals().get(nestedMethodName); 403 if (nestedMethodLocal !== undefined) { 404 this.updateLocalInfoWithClosures(nestedMethodLocal, outerMethod, nestedMethod, closuresLocal); 405 } else { 406 const nestedMethodGlobal = outerMethod.getBody()?.getUsedGlobals()?.get(nestedMethodName); 407 if (nestedMethodGlobal !== undefined && nestedMethodGlobal instanceof GlobalRef) { 408 this.updateGlobalInfoWithClosures(nestedMethodGlobal, outerMethod, nestedMethod, closuresLocal); 409 } 410 } 411 412 const originalMethodName = this.getOriginalNestedMethodName(nestedMethodName); 413 if (originalMethodName === null) { 414 return; 415 } 416 const originalMethodLocal = outerMethod.getBody()?.getLocals().get(originalMethodName); 417 if (originalMethodLocal !== undefined) { 418 this.updateLocalInfoWithClosures(originalMethodLocal, outerMethod, nestedMethod, closuresLocal); 419 } else { 420 const originalMethodGlobal = outerMethod.getBody()?.getUsedGlobals()?.get(originalMethodName); 421 if (originalMethodGlobal !== undefined && originalMethodGlobal instanceof GlobalRef) { 422 this.updateGlobalInfoWithClosures(originalMethodGlobal, outerMethod, nestedMethod, closuresLocal); 423 } 424 } 425 } 426 427 private getOriginalNestedMethodName(nestedMethodName: string): string | null { 428 if (nestedMethodName.startsWith(NAME_PREFIX) && nestedMethodName.includes(NAME_DELIMITER)) { 429 const nameComponents = nestedMethodName.slice(1).split(NAME_DELIMITER); 430 if (nameComponents.length > 1) { 431 return nameComponents[0]; 432 } 433 } 434 return null; 435 } 436 437 private updateGlobalInfoWithClosures(globalRef: GlobalRef, outerMethod: ArkMethod, nestedMethod: ArkMethod, closuresLocal: Local): void { 438 if (globalRef.getRef() !== null) { 439 return; 440 } 441 const methodSignature = nestedMethod.getImplementationSignature(); 442 if (methodSignature === null) { 443 return; 444 } 445 const lexicalEnv = closuresLocal.getType(); 446 if (!(lexicalEnv instanceof LexicalEnvType)) { 447 return; 448 } 449 const fieldSignature = new FieldSignature( 450 methodSignature.getMethodSubSignature().getMethodName(), 451 methodSignature.getDeclaringClassSignature(), 452 new ClosureType(lexicalEnv, methodSignature) 453 ); 454 globalRef.setRef(new ArkStaticFieldRef(fieldSignature)); 455 this.updateAbstractInvokeExprWithClosures(globalRef, outerMethod.getSignature(), nestedMethod.getSignature(), closuresLocal); 456 } 457 458 private updateLocalInfoWithClosures(local: Local, outerMethod: ArkMethod, nestedMethod: ArkMethod, closuresLocal: Local): void { 459 const localType = local.getType(); 460 if (!(localType instanceof FunctionType)) { 461 return; 462 } 463 464 const lexicalEnv = closuresLocal.getType(); 465 if (!(lexicalEnv instanceof LexicalEnvType)) { 466 return; 467 } 468 469 // 更新local的类型为ClosureType,methodSignature为内层嵌套函数 470 const nestedMethodSignature = nestedMethod.getImplementationSignature(); 471 if (nestedMethodSignature !== null) { 472 local.setType(new ClosureType(lexicalEnv, nestedMethodSignature, localType.getRealGenericTypes())); 473 } else { 474 local.setType(new ClosureType(lexicalEnv, localType.getMethodSignature(), localType.getRealGenericTypes())); 475 } 476 477 this.updateAbstractInvokeExprWithClosures(local, outerMethod.getSignature(), nestedMethod.getSignature(), closuresLocal); 478 } 479 480 // 更新所有stmt中调用内层函数处的AbstractInvokeExpr中的函数签名和实参args,加入闭包参数 481 // 更新所有stmt中定义的函数指针的usedStmt中的函数签名和实参args,加入闭包参数 482 private updateAbstractInvokeExprWithClosures( 483 value: Local | GlobalRef, 484 outerMethodSignature: MethodSignature, 485 nestedMethodSignature: MethodSignature, 486 closuresLocal: Local 487 ): void { 488 for (const usedStmt of value.getUsedStmts()) { 489 if (usedStmt instanceof ArkInvokeStmt) { 490 this.updateSignatureAndArgsInArkInvokeExpr(usedStmt, nestedMethodSignature, closuresLocal); 491 } else if (usedStmt instanceof ArkAssignStmt) { 492 const rightOp = usedStmt.getRightOp(); 493 if (rightOp instanceof AbstractInvokeExpr) { 494 this.updateSignatureAndArgsInArkInvokeExpr(usedStmt, nestedMethodSignature, closuresLocal); 495 } 496 const leftOp = usedStmt.getLeftOp(); 497 if (leftOp instanceof Local) { 498 leftOp.setType(rightOp.getType()); 499 } 500 } else if (usedStmt instanceof ArkReturnStmt) { 501 outerMethodSignature.getMethodSubSignature().setReturnType(value.getType()); 502 } 503 const defValue = usedStmt.getDef(); 504 if (defValue === null) { 505 continue; 506 } 507 if ((defValue instanceof Local || defValue instanceof GlobalRef) && defValue.getType() instanceof FunctionType) { 508 this.updateAbstractInvokeExprWithClosures(defValue, outerMethodSignature, nestedMethodSignature, closuresLocal); 509 } 510 } 511 } 512 513 private createNewSignatureWithClosures(closuresLocal: Local, oldSignature: MethodSignature): MethodSignature { 514 let oldSubSignature = oldSignature.getMethodSubSignature(); 515 const params = oldSubSignature.getParameters(); 516 const closuresParam = new MethodParameter(); 517 closuresParam.setName(closuresLocal.getName()); 518 closuresParam.setType(closuresLocal.getType()); 519 params.unshift(closuresParam); 520 let newSubSignature = new MethodSubSignature(oldSubSignature.getMethodName(), params, oldSubSignature.getReturnType(), oldSubSignature.isStatic()); 521 return new MethodSignature(oldSignature.getDeclaringClassSignature(), newSubSignature); 522 } 523 524 private updateSignatureAndArgsInArkInvokeExpr(stmt: ArkInvokeStmt | ArkAssignStmt, methodSignature: MethodSignature, closuresLocal: Local): void { 525 let expr: AbstractInvokeExpr; 526 if (stmt instanceof ArkInvokeStmt) { 527 expr = stmt.getInvokeExpr(); 528 } else { 529 const rightOp = stmt.getRightOp(); 530 if (!(rightOp instanceof AbstractInvokeExpr)) { 531 return; 532 } 533 expr = rightOp; 534 } 535 const exprMethodName = expr.getMethodSignature().getMethodSubSignature().getMethodName(); 536 const nestedMethodName = methodSignature.getMethodSubSignature().getMethodName(); 537 if (exprMethodName === nestedMethodName) { 538 expr.setMethodSignature(this.createNewSignatureWithClosures(closuresLocal, methodSignature)); 539 expr.getArgs().unshift(closuresLocal); 540 closuresLocal.addUsedStmt(stmt); 541 return; 542 } 543 544 const originalMethodName = this.getOriginalNestedMethodName(nestedMethodName); 545 if (originalMethodName !== null) { 546 if (exprMethodName === originalMethodName || expr instanceof ArkPtrInvokeExpr) { 547 expr.setMethodSignature(methodSignature); 548 expr.getArgs().unshift(closuresLocal); 549 closuresLocal.addUsedStmt(stmt); 550 } 551 } 552 } 553 554 private addClosureParamsAssignStmts(closuresParam: Local, method: ArkMethod): void { 555 const lexicalEnv = closuresParam.getType(); 556 if (!(lexicalEnv instanceof LexicalEnvType)) { 557 return; 558 } 559 const closures = lexicalEnv.getClosures(); 560 if (closures.length === 0) { 561 return; 562 } 563 const oldParamRefs = method.getParameterRefs(); 564 let body = method.getBody(); 565 if (body === undefined) { 566 return; 567 } 568 let stmts = Array.from(body.getCfg().getBlocks())[0].getStmts(); 569 let index = 0; 570 const parameterRef = new ArkParameterRef(index, lexicalEnv); 571 const closuresLocal = new Local(closuresParam.getName(), lexicalEnv); 572 body.addLocal(closuresLocal.getName(), closuresLocal); 573 let assignStmt = new ArkAssignStmt(closuresLocal, parameterRef); 574 assignStmt.setCfg(body.getCfg()); 575 stmts.splice(index, 0, assignStmt); 576 closuresLocal.setDeclaringStmt(assignStmt); 577 578 oldParamRefs?.forEach(paramRef => { 579 index++; 580 paramRef.setIndex(index); 581 }); 582 583 for (let closure of closures) { 584 let local = body.getLocals().get(closure.getName()); 585 if (local === undefined) { 586 local = new Local(closure.getName(), closure.getType()); 587 body.addLocal(local.getName(), local); 588 } else { 589 local.setType(closure.getType()); 590 } 591 index++; 592 const closureFieldRef = new ClosureFieldRef(closuresParam, closure.getName(), closure.getType()); 593 let assignStmt = new ArkAssignStmt(local, closureFieldRef); 594 assignStmt.setCfg(body.getCfg()); 595 stmts.splice(index, 0, assignStmt); 596 local.setDeclaringStmt(assignStmt); 597 closuresLocal.addUsedStmt(assignStmt); 598 } 599 } 600} 601