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 17import type { RawSourceMap } from 'typescript'; 18import Benchmark from 'benchmark'; 19import { 20 ArkObfuscator, 21 renameIdentifierModule 22} from '../../src/ArkObfuscator'; 23import { 24 decodeSourcemap, 25 mergeSourceMap, 26 Source, 27 SourceMapLink 28} from '../../src/utils/SourceMapMergingUtil'; 29import { 30 IDENTIFIER_CACHE, 31 MEM_METHOD_CACHE, 32} from '../../src/utils/NameCacheUtil'; 33 34const benchmarkSuite = new Benchmark.Suite; 35const namePaddingSize: number = 56; 36const dataPaddingSize: number = 16; 37 38const previousMap = { 39 version: 3, 40 file: 'EntryAbility.ts', 41 sourceRoot: '', 42 sources: [ 'entry/src/main/ets/entryability/EntryAbility.ts' ], 43 names: [], 44 mappings: 'OAAO,SAAS;OACT,KAAK;YACL,MAAM;AAEb,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,SAAS;IACjD,QAAQ,CAAC,IAAI,EAAE,WAAW;' 45 + 'QACxB,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAC;IAClE,CAAC;' 46 + 'IAED,SAAS;QACP,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,CAAC,CAAC;' 47 + 'IACnE,CAAC;IAED,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW;QACjD,yDAAyD;' 48 + 'QACzD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,6BAA6B,CAAC,CAAC;' 49 + 'QAE3E,WAAW,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACnD,IAAI,GAAG,CAAC,IAAI,EAAE;' 50 + 'gBACZ,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,+CAA+C,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;' 51 + 'gBAC3G,OAAO;aACR;YACD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,oDAAoD,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;' 52 + 'QAClH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oBAAoB;QAClB,yDAAyD;QACzD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,8BAA8B,CAAC,CAAC;' 53 + 'IAC9E,CAAC;IAED,YAAY;QACV,oCAAoC;QACpC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC;IACtE,CAAC;' 54 + 'IAED,YAAY;QACV,iCAAiC;QACjC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC;IACtE,CAAC;CACF', 55 sourcesContent: undefined 56}; 57 58const currentMap = { 59 version: 3, 60 file: 'EntryAbility.ts', 61 sourceRoot: '', 62 sources: [ 63 'entry/build/default/cache/default/default@CompileArkTS/esmodule/release/entry/src/main/ets/entryability/EntryAbility.ts' 64 ], 65 names: [], 66 mappings: 'AAAA,OAAO,SAAS,MAAM,6BAA6B,CAAC;AACpD,OAAO,KAAK,MAAM,aAAa,CAAC;AAChC,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;' 67 + 'AACvC,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,SAAS;IAC/C,QAAQ,CAAC,CAAI,EAAE,CAAW;' 68 + 'QACtB,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAC;' 69 + 'IACpE,CAAC;IACD,SAAS;QACL,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,CAAC,CAAC;' 70 + 'IACrE,CAAC;IACD,mBAAmB,CAAC,GAAa,MAAM,CAAC,WAAW;QAE/C,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,6BAA6B,CAAC,CAAC;' 71 + 'QAC3E,EAAY,WAAW,CAAC,aAAa,EAAE,CAAC,CAAG,EAAE,CAAI,EAAE,EAAE;YACjD,IAAI,EAAI,IAAI,EAAE;' 72 + 'gBACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,+CAA+C,EAAE,IAAI,CAAC,SAAS,GAAK,IAAI,EAAE,CAAC,CAAC;' 73 + 'gBAC3G,OAAO;aACV;YACD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,oDAAoD,EAAE,IAAI,CAAC,SAAS,GAAM,IAAI,EAAE,CAAC,CAAC;' 74 + 'QACpH,CAAC,CAAC,CAAC;IACP,CAAC;IACD,oBAAoB;QAEhB,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,8BAA8B,CAAC,CAAC;' 75 + 'IAChF,CAAC;IACD,YAAY;QAER,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC;IACxE,CAAC;IACD,YAAY;' 76 + 'QAER,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC;IACxE,CAAC;CACJ', 77 sourcesContent: undefined 78}; 79 80renameIdentifierModule.nameCache = new Map([ 81 [ 82 'IdentifierCache', 83 new Map([ 84 ['EntryAbility#onWindowStageCreate#windowStage', 'a'], 85 ['EntryAbility#onWindowStageCreate#__function', 'b'], 86 ['EntryAbility#onWindowStageCreate#$0#err', 'c'], 87 ['EntryAbility#onWindowStageCreate#$0#data', 'd'], 88 ['EntryAbility#onCreate#want', 'e'], 89 ['EntryAbility#onCreate#launchParam', 'f'] 90 ]) 91 ], 92 [ 93 'MemberMethodCache', 94 new Map([ 95 ['onCreate:5:5:7:6', 'onCreate'], 96 ['onDestroy:8:5:10:6', 'onDestroy'], 97 ['onWindowStageCreate:11:5:20:6', 'onWindowStageCreate'], 98 ['onWindowStageDestroy:21:5:23:6', 'onWindowStageDestroy'], 99 ['onForeground:24:5:26:6', 'onForeground'], 100 ['onBackground:27:5:29:6', 'onBackground'] 101 ]) 102 ] 103]); 104 105function alignColumn(name, ops, variance, runsSampled) { 106 const namePadding = name.padEnd(namePaddingSize); 107 const opsPadding = ops.padEnd(dataPaddingSize); 108 const variancePadding = variance.padEnd(dataPaddingSize); 109 const runsSampledPadding = runsSampled.toString().padEnd(dataPaddingSize); 110 return `| ${namePadding} | ${opsPadding} | ${variancePadding} | ${runsSampledPadding} |`; 111} 112 113class ArkObfuscatorMock extends ArkObfuscator { 114 convertLineBasedOnSourceMapMock(targetCache: string, sourceMapLink?: SourceMapLink): Map<string, string> { 115 // Ignore `property is private and only accessible within class` error 116 // @ts-ignore 117 return this.convertLineBasedOnSourceMap(targetCache, sourceMapLink); 118 } 119}; 120 121describe('SourceMap Benchmark Test', function() { 122 after(() => { 123 benchmarkSuite.on('complete', function() { 124 console.log('\n Benchmark Summary Results:\n'); 125 console.log(' ', alignColumn('Test Name', 'Ops/Sec', 'Variance', 'Number of Runs')); 126 console.log(' ',alignColumn('-'.repeat(namePaddingSize), '-'.repeat(dataPaddingSize), 127 '-'.repeat(dataPaddingSize), '-'.repeat(dataPaddingSize))); 128 this.forEach(result => { 129 console.log(' ', alignColumn(result.name, `${Math.round(result.hz)}`, 130 `${result.stats.rme.toFixed(2)}%`, result.stats.sample.length)); 131 }); 132 console.log('\n'); 133 }); 134 }); 135 136 it('run sourcemap benchmark test', function() { 137 let decodedSourceMap; 138 benchmarkSuite.add('decodeSourcemap', function() { 139 decodedSourceMap = decodeSourcemap(previousMap as RawSourceMap); 140 }); 141 142 benchmarkSuite.add('mergeSourceMap', function() { 143 mergeSourceMap(previousMap as RawSourceMap, currentMap as RawSourceMap); 144 }); 145 146 benchmarkSuite.add('convertLineBasedOnSourceMap', function() { 147 const sourceFileName = previousMap.sources?.length === 1 ? previousMap.sources[0] : ''; 148 const source = new Source(sourceFileName, null); 149 const sourceMapLink = new SourceMapLink(decodedSourceMap!, [source]); 150 const arkObfuscator = new ArkObfuscatorMock(); 151 arkObfuscator.convertLineBasedOnSourceMapMock(IDENTIFIER_CACHE, sourceMapLink); 152 arkObfuscator.convertLineBasedOnSourceMapMock(MEM_METHOD_CACHE, sourceMapLink); 153 }); 154 155 benchmarkSuite.on('cycle', (event: any) => { 156 console.log(' ', String(event.target)); 157 }); 158 159 benchmarkSuite.run({ 'async': true }); 160 }); 161});