├── tests ├── misc.ts ├── 14.phi.ts ├── 9.hotcompile.ts ├── 12.iterator.ts ├── 1.normal.ts ├── 4.if.ts ├── 15.sendable.ts ├── 11.generator.ts ├── 16.async.ts ├── 5.trycatch.ts ├── 13.differentbranchcases.ts ├── 7.lexical.ts ├── 3.func.ts ├── 10.module.ts ├── 2.array_obj.ts ├── 6.loop.ts └── 8.class.ts ├── demo.png ├── .gitmodules ├── hot.sh ├── .gitignore ├── run.sh ├── algos.h ├── loopconstruction.h ├── classconstruction.h ├── complexstmt2body.h ├── genlogs.sh ├── scripts ├── prepare.sh ├── removebc.py ├── picktokens.py ├── tokens.txt ├── pickintrinsics.py ├── draw_cfg.py └── intrinsic_list.txt ├── modulevar.h ├── patches ├── arkcompiler_runtime_core_a94c360.patch └── third_party_protobuf_0e4c27.patch ├── docker └── Dockerfile ├── BUILD.gn ├── algos.cpp ├── lexicalenv.h ├── base.h ├── loopconstruction.cpp ├── base.cpp ├── autotests ├── count_json_members.py └── scantstests.py ├── fundepscan.h ├── fundepscan.cpp ├── astgen_auxiins.cpp ├── ast.h ├── classconstruction.cpp ├── arkts.h ├── intrinsicid2token.h ├── lexicalenv.cpp ├── README.md ├── LICENSE ├── modulevar.cpp └── xabc.cpp /tests/misc.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/arkdecompiler/HEAD/demo.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "autotests/third_party_typescript"] 2 | path = autotests/third_party_typescript 3 | url = https://gitcode.com/openharmony/third_party_typescript.git 4 | -------------------------------------------------------------------------------- /hot.sh: -------------------------------------------------------------------------------- 1 | ../out/x64.debug/arkcompiler/ets_frontend/es2abc --module --dump-symbol-table base.map --output 1.abc 1.ts 2 | ../out/x64.debug/arkcompiler/ets_frontend/es2abc --module --hot-reload --input-symbol-table base.map --output demo.abc 2.ts 3 | ../out/x64.debug/arkcompiler/runtime_core/ark_disasm demo.abc demo.pa 4 | rm 1.abc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | base.map 2 | a 3 | 4 | scripts/*.ir 5 | scripts/out/* 6 | 7 | repos/* 8 | logs/* 9 | out/* 10 | 11 | autotests/*.ts 12 | autotests/*.ast 13 | autotests/*.abc 14 | autotests/*.json 15 | autotests/status_outputs/* 16 | 17 | 18 | 19 | .vscode 20 | *.abc 21 | *.log 22 | *.o 23 | *.xml 24 | *.pa 25 | *.abc 26 | *.ts 27 | *.ast 28 | *.swp 29 | 30 | !tests/*.ts 31 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm demo.abc 3 | 4 | logdir=logs 5 | 6 | if [ "$1" = "module" ]; then 7 | ./genlogs.sh $logdir $1 8 | elif [ "$1" = "hot" ]; then 9 | ./hot.sh 10 | else 11 | ./genlogs.sh $logdir 12 | fi 13 | 14 | ninja -w dupbuild=warn xabc -C out 15 | LD_LIBRARY_PATH=./out/arkcompiler/runtime_core:./out/thirdparty/zlib ./out/arkcompiler/common/xabc 16 | python3 scripts/removebc.py -------------------------------------------------------------------------------- /tests/14.phi.ts: -------------------------------------------------------------------------------- 1 | // #21. phi 2 | // function add(a, b, c) { 3 | // var x; 4 | // var y; 5 | // if(c){ 6 | // x = a; 7 | // }else{ 8 | // x = b; 9 | // } 10 | // y = x; 11 | // return y; 12 | // } 13 | 14 | 15 | // phi in loop 16 | // var x = 0; 17 | // for (let i = 0; i < 5; i++) { 18 | // if (i === 2) { 19 | // x = 1; 20 | // continue; 21 | // } 22 | // x = 2; 23 | // } 24 | // x = 3; -------------------------------------------------------------------------------- /tests/9.hotcompile.ts: -------------------------------------------------------------------------------- 1 | // ./hot.sh && ./run.sh hot 2 | // 1. ts 3 | // incremental compile: base.ts 4 | // let a = 1; 5 | // let b = 1; 6 | // let c = 1; 7 | // function A() { 8 | // let d = a + b; 9 | // let e = 3; 10 | // let m = d + e; 11 | // return m; 12 | // } 13 | 14 | 15 | // 2.ts 16 | // let a = 1; 17 | // let b = 2; 18 | // let c = 3; 19 | // let n = 4; 20 | // function A() { 21 | // let d = a + b + c; 22 | // let e = 5; 23 | // let m = d + e + n; 24 | // return m; 25 | // } 26 | 27 | -------------------------------------------------------------------------------- /tests/12.iterator.ts: -------------------------------------------------------------------------------- 1 | // 46. iterator 2 | // let [a, b] = [1, 2]; 3 | 4 | // es2panda\test\parser\binder\loop-scope-name-js.js 5 | // while ((() => {return true})()) { 6 | // function foo() {} 7 | // } 8 | 9 | // for (let i = (() => {return 1})(); i < 5; i++) { 10 | // function foo1() {} 11 | // } 12 | 13 | 14 | // 47. getpropiterator getnextpropname 15 | // const list = [] 16 | // for(let x in list) { 17 | // console.log(x); 18 | // } 19 | 20 | 21 | // 48. getiterator 22 | // var list = [] 23 | // for(var x of list) { 24 | // console.log("hi"); 25 | // } 26 | -------------------------------------------------------------------------------- /algos.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_LCA 2 | #define DECOMPILER_LCA 3 | 4 | #include "base.h" 5 | 6 | class LCAFinder { 7 | public: 8 | LCAFinder(panda::compiler::Graph* graph); 9 | panda::compiler::BasicBlock* FindLCA(panda::compiler::BasicBlock* u, panda::compiler::BasicBlock* v); 10 | 11 | private: 12 | panda::compiler::Graph* graph; 13 | std::unordered_map> ancestors; 14 | 15 | void Initialize(); 16 | }; 17 | 18 | std::vector TopologicalSort(const std::vector>& edges); 19 | #endif -------------------------------------------------------------------------------- /loopconstruction.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_LOOPCONSTRUCTION 2 | #define DECOMPILER_LOOPCONSTRUCTION 3 | 4 | #include "base.h" 5 | 6 | namespace panda::compiler { 7 | 8 | void LogLoopBBs(BasicBlock* header); 9 | 10 | void JudgeLoopType(BasicBlock* header, std::map& loop2type, 11 | std::map &loop2exit, 12 | std::map &backedge2dowhileloop); 13 | 14 | void LogBackEdgeId(ArenaVector backedges); 15 | 16 | BasicBlock* SearchPreHeader(BasicBlock* header); 17 | 18 | bool LoopContainBlock(Loop* loop, BasicBlock *bb); 19 | 20 | } 21 | #endif -------------------------------------------------------------------------------- /tests/1.normal.ts: -------------------------------------------------------------------------------- 1 | // #1. CONST 2 | // const pi: number = 3.14159; 3 | 4 | // #2. Bin and Unary 5 | // let c; 6 | // c = 1 + 1; 7 | // let d = true; 8 | // let e = false; 9 | // let f = null; 10 | // let g = undefined; 11 | // var obj9 = NaN; 12 | // var obj10 = Infinity; 13 | // c = 3 * 9; 14 | // let h = ~ 1; 15 | // let i = 2; 16 | // i--; 17 | // i++; 18 | 19 | // #3. typeof 20 | // let j = 3; 21 | // let h = typeof j; 22 | 23 | // #4. instanceof 24 | // var str = "Hello, World!"; 25 | // var b = str instanceof Number; 26 | 27 | 28 | // #17. enum 29 | // enum Role { 30 | // A, 31 | // B, 32 | // C 33 | // } -------------------------------------------------------------------------------- /tests/4.if.ts: -------------------------------------------------------------------------------- 1 | // #18. IfImm 2 | // var x; 3 | // var y; 4 | // if(x){ 5 | // y = console.log("true"); 6 | // y = console.log("1"); 7 | // }else{ 8 | // y = console.log("false"); 9 | // } 10 | 11 | 12 | // #19. nested struct 13 | // var x; 14 | // var y; 15 | // var k; 16 | // if(x){ 17 | // y = 1; 18 | // if(k){ 19 | // y = 2; 20 | // y = 3; 21 | // }else{ 22 | // y = 4; 23 | // } 24 | // y = 5; 25 | // }else{ 26 | // if(k){ 27 | // y = 6; 28 | // y = 7; 29 | // }else{ 30 | // y = 8; 31 | // } 32 | // y = 9; 33 | // } 34 | // y = 10; 35 | -------------------------------------------------------------------------------- /classconstruction.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_CLASSCONSTRUCTION 2 | #define DECOMPILER_CLASSCONSTRUCTION 3 | 4 | 5 | #include "base.h" 6 | using namespace panda; 7 | using namespace bytecodeopt; 8 | 9 | bool ConstructClasses(std::map> &class2memberfuns, panda::es2panda::parser::Program *parser_program, BytecodeOptIrInterface *ir_interface, 10 | std::map &class2father, std::map &method2scriptfunast, 11 | std::map &ctor2classdeclast, std::map& raw2newname 12 | ); 13 | 14 | #endif -------------------------------------------------------------------------------- /complexstmt2body.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_COMPLEX2BODY 2 | #define DECOMPILER_COMPLEX2BODY 3 | 4 | #include "base.h" 5 | 6 | es2panda::ir::BlockStatement* ComplexStmt2Body(panda::es2panda::compiler::ir *astnode){ 7 | switch(astnode->Type()){ 8 | case AstNodeType::DO_WHILE_STATEMENT: 9 | return astnode->AsDoWhileStatement()->Body(); 10 | break; 11 | case AstNodeType::FOR_IN_STATEMENT: 12 | return astnode->AsForInStatement()->Body(); 13 | break; 14 | case AstNodeType::FOR_OF_STATEMENT: 15 | return astnode->AsForOfStatement()->Body(); 16 | break; 17 | 18 | default :; 19 | } 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /genlogs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | MODULE_OPTION=$2 3 | 4 | if [ "$MODULE_OPTION" = "module" ]; then 5 | ../out/x64.release/arkcompiler/ets_frontend/es2abc --module --dump-assembly demo.ts --output demo.abc > $1/demo.pa.raw 6 | ../out/x64.release/arkcompiler/ets_frontend/es2abc --module --dump-ast demo.ts --output demo.abc > $1/demo.ast 7 | ../out/x64.release/arkcompiler/runtime_core/ark_disasm demo.abc demo.pa 8 | else 9 | ../out/x64.release/arkcompiler/ets_frontend/es2abc --dump-assembly demo.ts --output demo.abc > $1/demo.pa.raw 10 | ../out/x64.release/arkcompiler/ets_frontend/es2abc --dump-ast demo.ts --output demo.abc > $1/demo.ast 11 | ../out/x64.release/arkcompiler/runtime_core/ark_disasm demo.abc demo.pa 12 | fi 13 | -------------------------------------------------------------------------------- /tests/15.sendable.ts: -------------------------------------------------------------------------------- 1 | // 31. sendable 2 | // class SendableB { 3 | // constructor() { 4 | // "use sendable"; 5 | // } 6 | 7 | // hello(){ 8 | // this.name = "hello"; 9 | // console.log("11"); 10 | // } 11 | // } 12 | 13 | // function test2() { 14 | // var a = new SendableB(); 15 | // var b = 1; 16 | // function hi() { 17 | // var m = a; 18 | // console.log(m); 19 | // var n = b; 20 | // console.log(n); 21 | // } 22 | // } 23 | 24 | // 32. ldsendableclass DEFINEPROPERTYBYNAME 25 | // class B { 26 | // constructor() { 27 | // "use sendable"; 28 | // } 29 | // static b: number = 1; 30 | // b: number = B.b; 31 | // //c: number = B["b"]; 32 | // } -------------------------------------------------------------------------------- /tests/11.generator.ts: -------------------------------------------------------------------------------- 1 | // 43. asyncfunctionenter asyncfunctionresolve asyncfunctionreject asyncfunctionawaituncaught 2 | 3 | // async function asyncFoo() { 4 | // const result = await myPromise; 5 | // console.log(result); 6 | // } 7 | 8 | 9 | // 44. creategeneratorobj suspendgenerator resumegenerator getresumemode createiterresultobj 10 | // function* generateFunc() { 11 | // yield 'hello'; 12 | // yield 'world'; 13 | // return 'done'; 14 | // } 15 | 16 | // const generator = generateFunc(); 17 | // console.log(generator.next()); 18 | 19 | 20 | // 45. createasyncgeneratorobj asyncgeneratorresolve asyncgeneratorreject setgeneratorstate 21 | // async function* asyncGenerateFunc(){ 22 | // yield 'hello'; 23 | // //return await "hello"; 24 | // } 25 | 26 | 27 | -------------------------------------------------------------------------------- /scripts/prepare.sh: -------------------------------------------------------------------------------- 1 | 2 | # https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-arkcompiler-guide.md 3 | 4 | intall_deps(){ 5 | sudo apt-get update && sudo apt-get install python ruby python3-pip git-lfs gcc-multilib g++-multilib zlib1g-dev libc++1 curl nodejs 6 | } 7 | 8 | intall_repo(){ 9 | mkdir ~/bin/ 10 | curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > ~/bin/repo 11 | chmod a+x ~/bin/repo 12 | export PATH=~/bin:$PATH 13 | pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple requests 14 | } 15 | 16 | download_source(){ 17 | 18 | repo init -u https://gitee.com/ark-standalone-build/manifest.git -b master 19 | repo sync -c -j8 20 | repo forall -c 'git lfs pull' 21 | 22 | ./prebuilts_download.sh 23 | } 24 | 25 | intall_deps 26 | intall_repo 27 | download_source 28 | 29 | #python3 ark.py x64.release 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/16.async.ts: -------------------------------------------------------------------------------- 1 | // 43. asyncfunctionenter asyncfunctionresolve asyncfunctionreject asyncfunctionawaituncaught 2 | 3 | // async function asyncFoo() { 4 | // const result = await myPromise; 5 | // console.log(result); 6 | // } 7 | 8 | // 44. creategeneratorobj suspendgenerator resumegenerator getresumemode createiterresultobj 9 | // function* generateFunc() { 10 | // yield 'hello'; 11 | // yield 'world'; 12 | // return 'done'; 13 | // } 14 | 15 | // const generator = generateFunc(); 16 | // console.log(generator.next()); 17 | 18 | // 45. createasyncgeneratorobj asyncgeneratorresolve asyncgeneratorreject setgeneratorstate 19 | // async function* asyncGenerateFunc(){ 20 | // yield 'hello'; 21 | // //return await "hello"; 22 | // } 23 | 24 | // 46.1 iterator delegation 25 | // class C4 { 26 | // async * f() { 27 | // const x = yield* [1]; 28 | // } 29 | // } 30 | 31 | // 46.2 iterator delegation 32 | // async function* f() { 33 | // const x = yield *[1]; 34 | // } 35 | -------------------------------------------------------------------------------- /tests/5.trycatch.ts: -------------------------------------------------------------------------------- 1 | // #20.1 try-catch 2 | // var x; 3 | // try { 4 | // x = 1; 5 | // } catch (error) { 6 | // x = 2; 7 | // } 8 | // x= 5; 9 | 10 | // #20.2 try-catch with catchphi 11 | // var x; 12 | // try { 13 | // x = 1; 14 | // } catch (error) { 15 | // x = console.log(error); 16 | // } 17 | // x= 5; 18 | 19 | // #20.3 try-catch with if-else 20 | // var k; 21 | // var x; 22 | // try { 23 | // x = 1; 24 | // } catch (error1) { 25 | // if(k){ 26 | // x = 2; 27 | // }else{ 28 | // x = 3; 29 | // } 30 | // x = 4; 31 | // } 32 | // x= 5; 33 | 34 | // #20.4 try-catch 35 | // var x; 36 | // try { 37 | // x = 1; 38 | // } catch (error) { 39 | // x = 2; 40 | // } 41 | // finally{ 42 | // x = 3; 43 | // } 44 | // x= 4; 45 | 46 | 47 | // #20.5 try-catch 48 | // var k; 49 | // var x; 50 | // try { 51 | // x = 1; 52 | // } catch (error1) { 53 | // if(k){ 54 | // x = 2; 55 | // }else{ 56 | // x = 3; 57 | // } 58 | // x = 4; 59 | // } 60 | // finally{ 61 | // x = 5; 62 | // } 63 | // x= 6; -------------------------------------------------------------------------------- /tests/13.differentbranchcases.ts: -------------------------------------------------------------------------------- 1 | // while case 1 a 2 | // const list = [] 3 | // for(let x in list) { 4 | // console.log(x); 5 | // } 6 | 7 | // while case 1 8 | // var x = 0; 9 | // var i = 0; 10 | // while (i < 5) { 11 | // x = i; 12 | // i = i + 1; 13 | // } 14 | // x = 10; 15 | 16 | // while case 2 17 | // var x = 0 18 | // var i = 0; 19 | // while (true) { 20 | // i++; 21 | // if (i === 5) { 22 | // x = i; 23 | // break; 24 | // } 25 | // x = 1; 26 | // } 27 | // x = 3; 28 | 29 | // if case 1 30 | // var x; 31 | // var y; 32 | // if(x){ 33 | // y = console.log("true"); 34 | // y = console.log("1"); 35 | // } 36 | 37 | // if case 2 38 | // var x; 39 | // var y; 40 | // if(x == undefined){ 41 | // y = console.log("1"); 42 | // }else{ 43 | // y = console.log("2"); 44 | // } 45 | 46 | // if case 3 47 | // var x; 48 | // var y; 49 | // if(x){ 50 | // y = console.log("true"); 51 | // y = console.log("1"); 52 | // }else{ 53 | // y = console.log("false"); 54 | // } 55 | 56 | 57 | // do while case 1 58 | // var i = 0; 59 | // var x = 1; 60 | // do { 61 | // x = 1 62 | // i++; 63 | // } while (i < 5); 64 | // x = 2; -------------------------------------------------------------------------------- /scripts/removebc.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import shutil 4 | 5 | def remove_bc_data(input_file): 6 | temp_file = input_file + '.tmp' 7 | 8 | with open(input_file, 'r') as infile, open(temp_file, 'w') as outfile: 9 | for line in infile: 10 | bc_index = line.find('bc:') 11 | if bc_index != -1: 12 | line = line[:bc_index] 13 | line = line.rstrip() + '\n' 14 | outfile.write(line) 15 | 16 | shutil.move(temp_file, input_file) 17 | 18 | def main(): 19 | parser = argparse.ArgumentParser(description='Remove data after "bc:" in each line of a file and strip trailing whitespace.') 20 | parser.add_argument('-f', '--file', type=str, help='Input file name', default='logs/func_main_0:(any,any,any).ir') 21 | 22 | args = parser.parse_args() 23 | 24 | input_filename = args.file 25 | 26 | if not os.path.exists(input_filename): 27 | print(f"Error: The file '{input_filename}' does not exist.") 28 | return 29 | 30 | remove_bc_data(input_filename) 31 | print(f"Processing complete. Changes applied to '{input_filename}'.") 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /tests/7.lexical.ts: -------------------------------------------------------------------------------- 1 | // # 25.1 newlexenv/poplexenv/stlexvar/ldlexvar 2 | // function hello() { 3 | // function hi() { 4 | // //for (var i = 0; i++ < 10;) { 5 | // var x1 = 21; 6 | // let x2 = function () { 7 | // return x1; 8 | // }; 9 | // //} 10 | // } 11 | // } 12 | 13 | // # 25.2 newlexenv/poplexenv/stlexvar/ldlexvar 14 | // (function () { 15 | // function f1() { 16 | // f3(); 17 | // } 18 | // function f3() { 19 | // } 20 | // function f5() {} 21 | // function f6(a) { 22 | // let v31 = a ; 23 | 24 | // function f19() { 25 | // let v36 = 21; 26 | // let v37 = function () { 27 | // return v36; 28 | // }; 29 | // for (var v33 = 0; v33++ < 10;) { 30 | // let v38 = 22; 31 | // let v39 = function () { 32 | // let v40 = v31; 33 | // f1(); 34 | // return v38; 35 | // }; 36 | // } 37 | // } 38 | 39 | // f19(); 40 | // } 41 | // for (var v1 = 0; v1 < 10; v1++) { 42 | // f6(); 43 | // } 44 | // f1(); 45 | // })(); -------------------------------------------------------------------------------- /tests/3.func.ts: -------------------------------------------------------------------------------- 1 | // #6. callargs callthis 2 | // var x1 = clearTimeout(); 3 | // var x2 = parseInt("42"); 4 | // var x3 = parseInt("1010", 2); 5 | // var x4 = parseInt("10", 10, 0); 6 | // var x5 = Math.random(); 7 | // var x6 = console.log("hello"); 8 | 9 | // #9. callarg1 tLoadString 10 | // var obj11 = BigInt("1234567890123456789012345678901234567890"); 11 | 12 | // 14. callthisrange callrange 13 | // var x= setInterval(Math.max, 2000, "Bob", "Hi"); 14 | // const maxNumber = Math.max(1,2,3,4,5,6,7); 15 | 16 | // #16. function declaration and DEFINEFUNC 17 | // function add(a: number, b: number): number { 18 | // return a + b; 19 | // } 20 | // var x = add(2, 3); 21 | 22 | 23 | // #23. function call def-use detection 24 | // console.log("hi"); 25 | // var x6 = console.log("hello"); 26 | 27 | 28 | // # 28. DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 29 | // function hello(){ 30 | // var x = 1; 31 | // } 32 | 33 | 34 | // 40. getunmappedargs 35 | // function exampleFunction(a, b) { 36 | // console.log(arguments.length); 37 | // console.log(arguments[0]); 38 | // console.log(arguments[1]); 39 | // } 40 | 41 | 42 | // 40. SUPERCALLARROWRANGE 43 | // function exampleFunction(a, b) { 44 | // console.log(arguments.length); 45 | // console.log(arguments[0]); 46 | // console.log(arguments[1]); 47 | // } 48 | -------------------------------------------------------------------------------- /scripts/picktokens.py: -------------------------------------------------------------------------------- 1 | import re 2 | import argparse 3 | from collections import OrderedDict 4 | import ipdb 5 | 6 | def process_intrinsic_cases(input_file, output_file): 7 | with open(input_file, 'r') as file: 8 | content = file.read() 9 | 10 | pattern = r'case\s+TokenType::(\w+):\s*return\s*"([^"]+)";' 11 | matches = re.findall(pattern, content) 12 | 13 | with open(output_file, 'w') as file: 14 | for match in matches: 15 | file.write(f"{match[0]}, {match[1]}\n") 16 | 17 | if __name__ == "__main__": 18 | parser = argparse.ArgumentParser( 19 | description='Process compiler intrinsic case statements with default file paths', 20 | formatter_class=argparse.RawTextHelpFormatter) 21 | 22 | 23 | #es2panda/lexer/token/token.cpp 24 | parser.add_argument('input', 25 | nargs='?', 26 | default='../../arkcompiler/ets_frontend/es2panda/lexer/token/token.cpp', 27 | help='Input file path (default: %(default)s)') 28 | 29 | parser.add_argument('output', 30 | nargs='?', 31 | default='tokens.txt', 32 | help='Output file path (default: %(default)s)') 33 | 34 | args = parser.parse_args() 35 | process_intrinsic_cases(args.input, args.output) 36 | 37 | -------------------------------------------------------------------------------- /modulevar.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_MODULEVAR 2 | #define DECOMPILER_MODULEVAR 3 | 4 | #include "base.h" 5 | 6 | using namespace panda; 7 | 8 | std::string GetStringByOffset(std::unique_ptr& file_, uint32_t offset); 9 | 10 | bool IsValidOffset(std::unique_ptr& file_, uint32_t offset); 11 | 12 | void AddImportAst(panda::es2panda::parser::Program *parser_program, std::string imported_name, std::string local_name, std::string module_name); 13 | 14 | void AddExportAstAll(panda::es2panda::parser::Program *parser_program, std::string module_name); 15 | 16 | void AddExportAstNamed(panda::es2panda::parser::Program *parser_program, std::string import_name, std::string export_name, std::string module_name); 17 | 18 | void AddExportAst(panda::es2panda::parser::Program *parser_program, std::string local_name, std::string export_name); 19 | 20 | void GetModuleLiteralArray(std::unique_ptr& file_, panda_file::File::EntityId &module_id, panda::disasm::Disassembler& disasm, 21 | panda::es2panda::parser::Program *parser_program, std::map>& index2namespaces, std::vector& localnamespaces); 22 | 23 | void ParseModuleVars(std::unique_ptr& file_, pandasm::Program *prog, panda::disasm::Disassembler& disasm, 24 | panda::es2panda::parser::Program *parser_program, std::map>& index2namespaces, std::vector& localnamespaces); 25 | 26 | #endif -------------------------------------------------------------------------------- /scripts/tokens.txt: -------------------------------------------------------------------------------- 1 | PUNCTUATOR_BITWISE_AND, & 2 | PUNCTUATOR_BITWISE_OR, | 3 | PUNCTUATOR_MULTIPLY, * 4 | PUNCTUATOR_DIVIDE, / 5 | PUNCTUATOR_MINUS, - 6 | PUNCTUATOR_EXCLAMATION_MARK, ! 7 | PUNCTUATOR_TILDE, ~ 8 | PUNCTUATOR_MINUS_MINUS, -- 9 | PUNCTUATOR_LEFT_SHIFT, << 10 | PUNCTUATOR_RIGHT_SHIFT, >> 11 | PUNCTUATOR_LESS_THAN_EQUAL, <= 12 | PUNCTUATOR_GREATER_THAN_EQUAL, >= 13 | PUNCTUATOR_MOD, % 14 | PUNCTUATOR_BITWISE_XOR, ^ 15 | PUNCTUATOR_EXPONENTIATION, ** 16 | PUNCTUATOR_MULTIPLY_EQUAL, *= 17 | PUNCTUATOR_EXPONENTIATION_EQUAL, **= 18 | PUNCTUATOR_DIVIDE_EQUAL, /= 19 | PUNCTUATOR_MOD_EQUAL, %= 20 | PUNCTUATOR_MINUS_EQUAL, -= 21 | PUNCTUATOR_LEFT_SHIFT_EQUAL, <<= 22 | PUNCTUATOR_RIGHT_SHIFT_EQUAL, >>= 23 | PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, >>> 24 | PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, >>>= 25 | PUNCTUATOR_BITWISE_AND_EQUAL, &= 26 | PUNCTUATOR_BITWISE_OR_EQUAL, |= 27 | PUNCTUATOR_LOGICAL_AND_EQUAL, &&= 28 | PUNCTUATOR_NULLISH_COALESCING, ?? 29 | PUNCTUATOR_LOGICAL_OR_EQUAL, ||= 30 | PUNCTUATOR_LOGICAL_NULLISH_EQUAL, \?\?= 31 | PUNCTUATOR_BITWISE_XOR_EQUAL, ^= 32 | PUNCTUATOR_PLUS, + 33 | PUNCTUATOR_PLUS_PLUS, ++ 34 | PUNCTUATOR_PLUS_EQUAL, += 35 | PUNCTUATOR_LESS_THAN, < 36 | PUNCTUATOR_GREATER_THAN, > 37 | PUNCTUATOR_EQUAL, == 38 | PUNCTUATOR_NOT_EQUAL, != 39 | PUNCTUATOR_STRICT_EQUAL, === 40 | PUNCTUATOR_NOT_STRICT_EQUAL, !== 41 | KEYW_INSTANCEOF, instanceof 42 | KEYW_IN, in 43 | PUNCTUATOR_LOGICAL_AND, && 44 | PUNCTUATOR_LOGICAL_OR, || 45 | PUNCTUATOR_SUBSTITUTION, = 46 | PUNCTUATOR_QUESTION_MARK, ? 47 | PUNCTUATOR_AT, @ 48 | KEYW_ANY, any 49 | KEYW_UNKNOWN, unknown 50 | KEYW_NEVER, never 51 | KEYW_NUMBER, number 52 | KEYW_BIGINT, bigint 53 | KEYW_BOOLEAN, boolean 54 | KEYW_STRING, string 55 | KEYW_VOID, void 56 | KEYW_OBJECT, object 57 | KEYW_TYPEOF, typeof 58 | KEYW_DELETE, delete 59 | KEYW_OUT, out 60 | -------------------------------------------------------------------------------- /scripts/pickintrinsics.py: -------------------------------------------------------------------------------- 1 | import re 2 | import argparse 3 | from collections import OrderedDict 4 | import ipdb 5 | 6 | def process_intrinsic_cases(input_file, output_file): 7 | with open(input_file, 'r') as file: 8 | content = file.read() 9 | 10 | # Regular expression to match case statements 11 | case_pattern = re.compile(r'case\s+BytecodeInstruction::Opcode::(\w+):') 12 | 13 | # Find all matches and store them in an OrderedDict to maintain order and ensure uniqueness 14 | matches = list(OrderedDict.fromkeys(case_pattern.findall(content))) 15 | 16 | # Separate matches into regular and deprecated 17 | regular_matches = [match for match in matches if not match.startswith('DEPRECATED')] 18 | deprecated_matches = [match for match in matches if match.startswith('DEPRECATED')] 19 | 20 | # Combine lists with regular matches first 21 | sorted_matches = regular_matches + deprecated_matches 22 | 23 | with open(output_file, 'w') as file: 24 | for match in sorted_matches: 25 | file.write(match + '\n') 26 | 27 | if __name__ == "__main__": 28 | parser = argparse.ArgumentParser( 29 | description='Process compiler intrinsic case statements with default file paths', 30 | formatter_class=argparse.RawTextHelpFormatter) 31 | 32 | parser.add_argument('input', 33 | nargs='?', 34 | default='../out/gen/arkcompiler/runtime_core/compiler/generated/inst_builder_gen.cpp', 35 | help='Input file path (default: %(default)s)') 36 | 37 | parser.add_argument('output', 38 | nargs='?', 39 | default='intrinsic_list.txt', 40 | help='Output file path (default: %(default)s)') 41 | 42 | args = parser.parse_args() 43 | process_intrinsic_cases(args.input, args.output) 44 | 45 | -------------------------------------------------------------------------------- /patches/arkcompiler_runtime_core_a94c360.patch: -------------------------------------------------------------------------------- 1 | diff --git a/BUILD.gn b/BUILD.gn 2 | index 8099f59ea..dfffd707e 100755 3 | --- a/BUILD.gn 4 | +++ b/BUILD.gn 5 | @@ -120,7 +120,6 @@ if (!ark_standalone_build) { 6 | # Common config for ark source 7 | config("ark_config") { 8 | visibility = [ 9 | - "*", 10 | "./*", 11 | "//arkcompiler/ets_frontend/*", 12 | ] 13 | @@ -365,14 +364,6 @@ group("ark_host_mac_defectscanaux_unittest") { 14 | } 15 | } 16 | 17 | -group("xabc") { 18 | - testonly = true 19 | - deps = [ 20 | - "//arkdecompiler:xabc", 21 | - ] 22 | -} 23 | - 24 | - 25 | group("runtime_core_host_unittest") { 26 | testonly = true 27 | deps = [ 28 | diff --git a/compiler/optimizer/ir/inst.h b/compiler/optimizer/ir/inst.h 29 | index 62627b14e..197195776 100644 30 | --- a/compiler/optimizer/ir/inst.h 31 | +++ b/compiler/optimizer/ir/inst.h 32 | @@ -1929,8 +1929,6 @@ public: 33 | } 34 | }; 35 | 36 | - 37 | - 38 | /** 39 | * CastAnyTypeValueInst instruction 40 | */ 41 | diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h 42 | index 3cd125540..e96089bdb 100644 43 | --- a/disassembler/disassembler.h 44 | +++ b/disassembler/disassembler.h 45 | @@ -87,7 +87,7 @@ public: 46 | std::vector GetColumnNumber(); 47 | std::vector GetLineNumber(); 48 | 49 | -public: 50 | +private: 51 | void GetLiteralArrays(); 52 | void FillLiteralArrayTable(panda_file::File::EntityId &id, size_t index); 53 | void FillLiteralData(pandasm::LiteralArray *lit_array, const panda_file::LiteralDataAccessor::LiteralValue &value, 54 | @@ -233,9 +233,8 @@ public: 55 | bool quiet_; 56 | bool skip_strings_; 57 | std::unordered_set module_literals_; 58 | - public: 59 | std::unordered_set module_request_phase_literals_; 60 | -//#include "disasm_plugins.inc" 61 | +#include "disasm_plugins.inc" 62 | }; 63 | } // namespace panda::disasm 64 | 65 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | # 设置环境变量 4 | ENV DEBIAN_FRONTEND=noninteractive \ 5 | LANG=C.UTF-8 \ 6 | ROOT_PATH=/root \ 7 | DIRECTORY_NAME=harmonyos \ 8 | GIT_REPO=https://github.com/jd-opensource/arkdecompiler.git \ 9 | PATH=/root/bin:/root/harmonyos/prebuilts/build-tools/linux-x86/bin:$PATH 10 | 11 | # 安装依赖 12 | RUN apt-get update && apt-get install -y \ 13 | python3 python3-pip ruby git-lfs gcc-multilib g++-multilib \ 14 | zlib1g-dev libc++1 curl nodejs \ 15 | && rm -rf /var/lib/apt/lists/* 16 | RUN ln -s /usr/bin/python3 /usr/bin/python 17 | # 配置 git 信息 18 | RUN git config --global user.email "you@example.com" \ 19 | && git config --global user.name "Your" 20 | 21 | # 安装 repo 工具 22 | RUN mkdir -p /root/bin \ 23 | && curl -L https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 -o /root/bin/repo \ 24 | && chmod a+x /root/bin/repo \ 25 | && pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple requests 26 | 27 | # 创建源码目录并进入 28 | WORKDIR /root/${DIRECTORY_NAME} 29 | 30 | # 初始化并同步 OpenHarmony 源码 31 | # 分支使用OpenHarmony-5.1.0-Release master分支有部分依赖的头文件被删除 32 | RUN repo init -u https://gitee.com/ark-standalone-build/manifest.git -b OpenHarmony-5.1.0-Release \ 33 | && repo sync -c -j8 \ 34 | && repo forall -c 'git lfs pull' \ 35 | && ./prebuilts_download.sh 36 | 37 | # 克隆 arkdecompiler 38 | RUN if [ ! -d arkdecompiler ]; then \ 39 | git clone ${GIT_REPO}; \ 40 | else \ 41 | cd arkdecompiler && git pull; \ 42 | fi 43 | 44 | # 打 patch 添加xabc进入构建目标,修改BUILD.gn 45 | RUN cp ./arkdecompiler/patches/arkcompiler_runtime_core_a94c360.patch ./arkcompiler/runtime_core/ \ 46 | && cp ./arkdecompiler/patches/third_party_protobuf_0e4c27.patch ./third_party/protobuf/ \ 47 | && cd /root/harmonyos/arkcompiler/runtime_core \ 48 | && git apply arkcompiler_runtime_core_a94c360.patch \ 49 | && cd /root/harmonyos/third_party/protobuf \ 50 | && git apply third_party_protobuf_0e4c27.patch 51 | 52 | # 修改 run_command.py默认使用python3 53 | RUN sed -i '1s|.*|#!/usr/bin/env python3|' /root/harmonyos/third_party/openssl/run_command.py 54 | 55 | CMD ["/bin/bash"] 56 | -------------------------------------------------------------------------------- /tests/10.module.ts: -------------------------------------------------------------------------------- 1 | // run.sh module 2 | 3 | // # 26. module var: import and export clause 4 | // import { a, b } from "./module_foo" 5 | // import * as c from "./module_bar" 6 | 7 | // import add from './math'; 8 | 9 | // # 26.1 other imports 10 | // import { a, b } from "./module_foo1" 11 | // import * as c from "./module_bar" 12 | // import { d, e } from "./module_foo2" 13 | // import { PI as Pi, add as sum } from './math'; 14 | // import { namedExport as h } from 'module-path' assert { type: 'int' }; 15 | 16 | // # 26.2 exports 17 | // export let i: number = 3; 18 | // export function add(a: number, b: number): number { 19 | // return a + b; 20 | // } 21 | // export default api; 22 | 23 | // export * from './utils'; 24 | // export * as UserService from './userService'; 25 | // export { a as b , d as d} from './logger'; 26 | 27 | 28 | // # 26. module: LDLOCALMODULEVAR_IMM8, STMODULEVAR_IMM8, LDEXTERNALMODULEVAR_IMM8, WIDE_LDLOCALMODULEVAR_PREF_IMM16, WIDE_STMODULEVAR_PREF_IMM16, WIDE_LDEXTERNALMODULEVAR_PREF_IMM16 29 | // import { a, b } from "./module_foo1" 30 | // import { d, e } from "./module_foo2" 31 | // export { a as b , d as d} from './logger'; 32 | 33 | // export let i: number = 3; 34 | // export let f: number = 3; 35 | // export let g: number = 4; 36 | // export * from './utils'; 37 | // export * as UserService from './userService'; 38 | 39 | // var x = a + b + d + e + f + Pi + sum; 40 | 41 | 42 | // 33. ldlazymodulevar 43 | // import lazy {a} from './a' 44 | // import {b} from './b' 45 | // import c from './a' 46 | // import lazy d from './c' 47 | // import lazy from './b' 48 | 49 | 50 | // console.log(b); 51 | // console.log(c); 52 | // console.log(d); 53 | 54 | // 34. ldsendablelocalmodulevar, ldlazysendablemodulevar and ldsendableexternalmodulevar 55 | // import lazy {a} from './a' 56 | // import {b} from './b' 57 | // import c from './c' 58 | // import lazy d from './d' 59 | // import e from './e' 60 | 61 | // import f from "./f" 62 | 63 | // class B { 64 | // constructor() { 65 | // "use sendable"; 66 | // } 67 | 68 | // foo() { 69 | // console.log(a); 70 | // console.log(b); 71 | // new f(); 72 | // console.log(c); 73 | // console.log(d); 74 | // } 75 | // } 76 | 77 | // console.log(e); 78 | 79 | // 35. DYNAMICIMPORT 80 | 81 | // import('./moduleName').then(module => { 82 | // module.someFunction(); 83 | // }).catch(error => { 84 | // console.error("Error loading module:", error); 85 | // }); -------------------------------------------------------------------------------- /tests/2.array_obj.ts: -------------------------------------------------------------------------------- 1 | // 5. createemptyarray createarraywithbuffer createemptyobject createobjectwithbuffer 2 | // var obj2 = {}; 3 | // var obj3 = []; 4 | // var obj4 = [1, 2, 3]; 5 | // var obj5 = {"a":1, "b":2, "c":3}; 6 | 7 | 8 | // #7. stobjbyvalue ldobjbyvalue 9 | // var obj6 = {"a":1, "b":2, "c":3}; 10 | // var c = obj6["a"]; 11 | // obj6["d"] = 4; 12 | 13 | 14 | // 8. isin stobjbyname 15 | // var obj7 = {"a":1, "b":2, "c":3}; 16 | // var obj8 = "a" in obj7; 17 | // obj7.a = 5 18 | 19 | 20 | // #15. DELOBJPROP 21 | // let obj = { a: 1, b: 2 }; 22 | // let result = delete obj.c; 23 | 24 | // #10. NEWOBJRANGE 25 | // const regex = new RegExp('pattern', 'flags'); 26 | 27 | // 11. COPYDATAPROPERTIES 28 | // const obj1 = { a: 1, b: 2, c: 3 }; 29 | // const obj2 = { b: 4, d: 5 }; 30 | // var merged = { e: 6, ...obj1, ...obj2 }; 31 | 32 | 33 | // 12. createarraywithbuffer 34 | // const numbers = [5, 6, 2, 3, 7]; 35 | // const max = Math.max.apply(null, numbers); 36 | 37 | 38 | // #13. starrayspread apply 39 | // const numbers = [10, 20, 30, 5, 15]; 40 | // const maxNumber = Math.max(1,2,3,...numbers); 41 | 42 | // # 24. stownbyvalue 43 | // const arr1 = [1, 2, 3]; 44 | // const arr2 = [...arr1, 4, 5]; 45 | 46 | // # 25. stownbyindex 47 | // var r1; 48 | // var r2; 49 | // var r3 = [1, r1, ...r2]; 50 | 51 | // 36. NEWOBJAPPLY_ 52 | // const countryInfo = ['USA', 'The Star-Spangled Banner', 'John Stafford Smith']; 53 | // const usa = new Country(...countryInfo); 54 | 55 | 56 | // 39. CREATEOBJECTWITHEXCLUDEDKEYS 57 | // function foo() 58 | // { 59 | // let {a, b, c, ...d} = {a:1, b:2, c:3, f:4, e:5} 60 | // } 61 | 62 | // const sourceObject = { a: 1, b: 2, c: 3, f: 4, e: 5 }; 63 | 64 | // let { a: alpha, b: beta, c: gamma, ...rest } = sourceObject; 65 | 66 | 67 | // console.log(alpha); 68 | // console.log(beta); 69 | // console.log(gamma); 70 | 71 | 72 | // 38. CREATEREGEXPWITHLITERAL 73 | // var x = 0x1; 74 | // var y = new RegExp("hello", x); 75 | 76 | 77 | // 36. NEWOBJAPPLY_ 78 | // const countryInfo = ['USA', 'The Star-Spangled Banner', 'John Stafford Smith']; 79 | // const usa = new Country(...countryInfo); 80 | 81 | // 38. CREATEREGEXPWITHLITERAL 82 | // var x = 0x1; 83 | // var y = new RegExp("hello", x); 84 | 85 | // 39. CREATEOBJECTWITHEXCLUDEDKEYS 86 | // function foo() 87 | // { 88 | // let {a, b, c, ...d} = {a:1, b:2, c:3, f:4, e:5} 89 | // } 90 | 91 | // const sourceObject = { a: 1, b: 2, c: 3, f: 4, e: 5 }; 92 | 93 | // let { a: alpha, b: beta, c: gamma, ...rest } = sourceObject; 94 | 95 | 96 | // console.log(alpha); 97 | // console.log(beta); 98 | // console.log(gamma); -------------------------------------------------------------------------------- /BUILD.gn: -------------------------------------------------------------------------------- 1 | import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") 2 | import("//arkcompiler/runtime_core/ark_config.gni") 3 | import("$ark_root/tests/test_helper.gni") 4 | 5 | ohos_shared_library("libarkdecompiler") { 6 | stack_protector_ret = false 7 | sources = ["decompiler.cpp"] 8 | 9 | #cflags_cc = [ "-std=c++17", "-frtti" ] 10 | 11 | configs = [ 12 | "$ark_root:ark_config", 13 | "$ark_root/libpandabase:arkbase_public_config", 14 | "$ark_root/libpandafile:arkfile_public_config", 15 | "$ark_root/assembler:arkassembler_public_config", 16 | "$ark_root/bytecode_optimizer:bytecodeopt_public_config", 17 | "$ark_root/compiler:arkcompiler_public_config", 18 | ] 19 | 20 | deps = [ 21 | "$ark_root/disassembler:arkdisassembler", 22 | "$ark_root/assembler:libarkassembler", 23 | "$ark_root/bytecode_optimizer:libarkbytecodeopt", 24 | "$ark_root/compiler:libarkcompiler", 25 | "$ark_root/libpandabase:libarkbase", 26 | "$ark_root/libpandafile:libarkfile", 27 | ] 28 | 29 | external_deps = [ sdk_libc_secshared_dep ] 30 | 31 | include_dirs = [ "$ark_root/compiler/optimizer" ] 32 | 33 | output_extension = "so" 34 | relative_install_dir = "ark" 35 | part_name = "runtime_core" 36 | subsystem_name = "arkcompiler" 37 | } 38 | 39 | ohos_executable("xabc") { 40 | #cflags_cc -= [ "-fno-rtti" ] 41 | #cflags_cc += [ "-frtti" ] 42 | #cflags_cc += ["-std=c++17"] 43 | 44 | sources = [ 45 | "xabc.cpp", 46 | "astgen.cpp", 47 | "arkts.cpp", 48 | "lexicalenv.cpp", 49 | "algos.cpp", 50 | "modulevar.cpp", 51 | "base.cpp", 52 | "fundepscan.cpp", 53 | "classconstruction.cpp", 54 | "loopconstruction.cpp" 55 | ] 56 | 57 | configs = [ 58 | "$ark_root:ark_config", 59 | "$ark_root/assembler:arkassembler_public_config", 60 | "$ark_root/bytecode_optimizer:bytecodeopt_public_config", 61 | "$ark_root/compiler:arkcompiler_public_config", 62 | "$ark_root/libpandabase:arkbase_public_config", 63 | "$ark_root/libpandafile:arkfile_public_config", 64 | "$ark_root/../ets_frontend/es2panda:es2abc_config_src", 65 | "$ark_root/../ets_frontend/es2panda:es2abc_config_common", 66 | "$ark_root/../ets_frontend/merge_abc:panda_assembly_proto_public_config", 67 | "$ark_root/../ets_frontend/merge_abc:proto_file_cpp_config", 68 | "$ark_root/../../third_party/protobuf:protobuf_config", 69 | ] 70 | 71 | deps = [ 72 | "$ark_root/disassembler:arkdisassembler", 73 | "$ark_root/assembler:libarkassembler", 74 | "$ark_root/bytecode_optimizer:libarkbytecodeopt", 75 | "$ark_root/compiler:libarkcompiler", 76 | "$ark_root/libpandabase:libarkbase", 77 | "$ark_root/libpandafile:libarkfile", 78 | "$ark_root/libpandafile:libarkfile", 79 | "$ark_root/../ets_frontend/es2panda:es2panda_lib", 80 | ] 81 | 82 | external_deps = [ sdk_libc_secshared_dep ] 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /algos.cpp: -------------------------------------------------------------------------------- 1 | #include "algos.h" 2 | #include "base.h" 3 | 4 | LCAFinder::LCAFinder(panda::compiler::Graph* graph) : graph(graph) { 5 | Initialize(); 6 | } 7 | 8 | panda::compiler::BasicBlock* LCAFinder::FindLCA(panda::compiler::BasicBlock* u, panda::compiler::BasicBlock* v) { 9 | std::unordered_set commonAncestors; 10 | const auto& ancestorsU = ancestors[u]; 11 | const auto& ancestorsV = ancestors[v]; 12 | 13 | for (auto ancestor : ancestorsU) { 14 | if (ancestorsV.count(ancestor)) { 15 | commonAncestors.insert(ancestor); 16 | } 17 | } 18 | 19 | panda::compiler::BasicBlock* lca = nullptr; 20 | int maxDepth = -1; 21 | for (auto ancestor : commonAncestors) { 22 | int depth = ancestors[ancestor].size(); 23 | if (depth > maxDepth) { 24 | maxDepth = depth; 25 | lca = ancestor; 26 | } 27 | } 28 | return lca; 29 | } 30 | 31 | void LCAFinder::Initialize() { 32 | for (auto node : graph->GetBlocksRPO()) { 33 | std::unordered_set nodeAncestors; 34 | for (auto parent : node->GetPredsBlocks()) { 35 | nodeAncestors.insert(parent); 36 | nodeAncestors.insert(ancestors[parent].begin(), ancestors[parent].end()); 37 | } 38 | ancestors[node] = nodeAncestors; 39 | } 40 | } 41 | 42 | 43 | std::vector TopologicalSort(const std::vector>& edges) { 44 | if (edges.empty()) { 45 | return {}; 46 | } 47 | 48 | std::unordered_set allNodes; 49 | for (const auto& edge : edges) { 50 | allNodes.insert(edge.first); 51 | allNodes.insert(edge.second); 52 | } 53 | 54 | if (allNodes.empty()) { 55 | return {}; 56 | } 57 | 58 | std::unordered_map> graph; 59 | std::unordered_map indegree; 60 | 61 | for (uint32_t node : allNodes) { 62 | indegree[node] = 0; 63 | } 64 | 65 | for (const auto& edge : edges) { 66 | graph[edge.first].push_back(edge.second); 67 | indegree[edge.second]++; 68 | } 69 | 70 | std::queue q; 71 | for (uint32_t node : allNodes) { 72 | if (indegree[node] == 0) { 73 | q.push(node); 74 | } 75 | } 76 | 77 | std::vector result; 78 | while (!q.empty()) { 79 | uint32_t node = q.front(); 80 | q.pop(); 81 | result.push_back(node); 82 | 83 | for (uint32_t neighbor : graph[node]) { 84 | indegree[neighbor]--; 85 | if (indegree[neighbor] == 0) { 86 | q.push(neighbor); 87 | } 88 | } 89 | } 90 | 91 | if (result.size() != allNodes.size()) { 92 | HandleError("#TopologicalSort: search failed"); 93 | return {}; 94 | } 95 | 96 | return result; 97 | } -------------------------------------------------------------------------------- /lexicalenv.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_LEXICAL_ENV_STACK 2 | #define DECOMPILER_LEXICAL_ENV_STACK 3 | 4 | #include "base.h" 5 | 6 | using panda::compiler::BasicBlock; 7 | using panda::compiler::Inst; 8 | using panda::compiler::Opcode; 9 | 10 | 11 | class LexicalEnv { 12 | public: 13 | std::vector expressions_; 14 | std::set indexes_; 15 | 16 | size_t capacity_; 17 | mutable size_t full_size_; 18 | 19 | public: 20 | explicit LexicalEnv(size_t capacity = 256); 21 | 22 | LexicalEnv(const LexicalEnv& other); 23 | 24 | std::string *& operator[](size_t index); 25 | const std::string* operator[](size_t index) const; 26 | 27 | bool IsFull() const; 28 | std::string* Get(size_t index) const; 29 | void Set(size_t index, std::string* expr); 30 | 31 | size_t Size() const; 32 | 33 | void AddIndexes(size_t index); 34 | 35 | bool IsValidIndex(size_t index) const; 36 | 37 | private: 38 | void CheckIndex(size_t index) const; 39 | }; 40 | 41 | 42 | class LexicalEnvStack { 43 | private: 44 | std::vector stack_; 45 | 46 | public: 47 | LexicalEnvStack(); 48 | LexicalEnvStack(const LexicalEnvStack& other); 49 | 50 | bool IsFull() const; 51 | 52 | ~LexicalEnvStack(); 53 | LexicalEnv* Push(size_t capacity); 54 | 55 | void Pop(); 56 | 57 | size_t Size() const; 58 | 59 | bool Empty() const; 60 | 61 | std::string* Get(size_t A, size_t B) const; 62 | 63 | bool IsSetSafe(size_t A, size_t B); 64 | void Set(size_t A, size_t B, std::string* expr); 65 | void SetIndexes(size_t A, std::set indexes); 66 | 67 | LexicalEnv& GetLexicalEnv(size_t A); 68 | 69 | const LexicalEnv& Top() const; 70 | 71 | LexicalEnv& Top(); 72 | void Clear(); 73 | 74 | private: 75 | void CheckIndex(size_t A, size_t B) const; 76 | void CheckStackIndex(size_t A) const; 77 | }; 78 | 79 | void DealWithGlobalLexicalWaitlist(uint32_t tier, uint32_t index, std::string closure_name, std::vector *globallexical_waitlist); 80 | 81 | void MergeMethod2LexicalMap(Inst* inst, std::map bb2lexicalenvstack, 82 | uint32_t source_methodoffset, uint32_t target_methodoffset, std::map>>* method2lexicalmap); 83 | 84 | void PrintInnerMethod2LexicalMap(std::map>>* method2lexicalmap, uint32_t methodoffset); 85 | 86 | uint32_t SearchStartposForCreatePrivateproperty(Inst *inst, std::map bb2lexicalenvstack, 87 | std::map>>* method2lexicalmap, uint32_t methodoffset); 88 | 89 | 90 | void CopyLexicalenvStack(uint32_t methodoffset_, Inst* inst, std::map* method2lexicalenvstack, 91 | std::map bb2lexicalenvstack, std::vector *globallexical_waitlist); 92 | 93 | #endif // LEXICAL_ENV_STACK_H -------------------------------------------------------------------------------- /base.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_BASE 2 | #define DECOMPILER_BASE 3 | 4 | #include "libpandabase/mem/arena_allocator.h" 5 | #include "libpandabase/mem/pool_manager.h" 6 | 7 | #include "libpandafile/class_data_accessor.h" 8 | #include "libpandafile/class_data_accessor-inl.h" 9 | #include "libpandafile/method_data_accessor.h" 10 | #include "libpandafile/module_data_accessor-inl.h" 11 | 12 | #include "libpandafile/file.h" 13 | #include "libpandafile/util/collect_util.h" 14 | 15 | #include "libpandabase/utils/logger.h" 16 | 17 | 18 | ///////////////////////////////////////////////////////////// 19 | #include "compiler/optimizer/ir/graph.h" 20 | #include "compiler/optimizer/pass.h" 21 | #include "compiler/optimizer/ir_builder/ir_builder.h" 22 | #include "compiler/optimizer/analysis/loop_analyzer.h" 23 | 24 | #include "compiler/optimizer/optimizations/branch_elimination.h" 25 | #include "compiler/optimizer/optimizations/cleanup.h" 26 | #include "compiler/optimizer/optimizations/lowering.h" 27 | #include "compiler/optimizer/optimizations/move_constants.h" 28 | #include "compiler/optimizer/optimizations/regalloc/reg_alloc.h" 29 | #include "compiler/optimizer/optimizations/vn.h" 30 | #include "constant_propagation/constant_propagation.h" 31 | #include "compiler/optimizer/ir/basicblock.h" 32 | #include "compiler/optimizer/ir/graph_visitor.h" 33 | #include "compiler/optimizer/ir/inst.h" 34 | #include "compiler/optimizer/ir/runtime_interface.h" 35 | 36 | ///////////////////////////////////////////////////////////// 37 | 38 | #include "bytecode_optimizer/ir_interface.h" 39 | #include "bytecode_optimizer/runtime_adapter.h" 40 | #include "bytecode_optimizer/bytecode_analysis_results.h" 41 | #include "bytecode_optimizer/bytecodeopt_options.h" 42 | #include "bytecode_optimizer/optimize_bytecode.h" 43 | #include "bytecode_optimizer/reg_acc_alloc.h" 44 | #include "bytecode_optimizer/reg_encoder.h" 45 | #include "bytecode_optimizer/tagged_value.h" 46 | #include "bytecode_optimizer/codegen.h" 47 | #include "bytecode_optimizer/common.h" 48 | 49 | ///////////////////////////////////////////////////////////// 50 | #include "assembler/annotation.h" 51 | #include "assembler/assembly-function.h" 52 | #include "assembler/assembly-ins.h" 53 | #include "assembly-parser.h" 54 | #include "assembler/assembly-parser.h" 55 | 56 | #include "disassembler/disassembler.h" 57 | 58 | #include "ast.h" 59 | 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | static int count = 0; 70 | 71 | inline void HandleInnerError(const std::string& message) { 72 | std::cerr << "Error: " << message << std::endl; 73 | std::exit(EXIT_FAILURE); 74 | } 75 | 76 | template 77 | std::string formatString(Args... args) { 78 | std::ostringstream oss; 79 | int unpack[] = {0, ((void)(oss << args), 0)...}; 80 | static_cast(unpack); 81 | return oss.str(); 82 | } 83 | 84 | template 85 | void HandleError(Args... args) { 86 | std::ostringstream oss; 87 | oss << formatString(args...); 88 | HandleInnerError(oss.str()); 89 | } 90 | 91 | 92 | std::string RemoveArgumentsOfFunc(const std::string& input); 93 | std::optional> GetLiteralArrayByOffset(panda::pandasm::Program* program, uint32_t offset); 94 | std::optional FindKeyByValue(const std::map& myMap, const uint32_t& value); 95 | 96 | uint32_t ParseHexFromKey(const std::string& key); 97 | #endif -------------------------------------------------------------------------------- /patches/third_party_protobuf_0e4c27.patch: -------------------------------------------------------------------------------- 1 | diff --git a/BUILD.gn b/BUILD.gn 2 | index 212ac82..6864bc1 100644 3 | --- a/BUILD.gn 4 | +++ b/BUILD.gn 5 | @@ -11,7 +11,8 @@ 6 | # See the License for the specific language governing permissions and 7 | # limitations under the License. 8 | 9 | -import("//build/ohos.gni") 10 | +import("//arkcompiler/runtime_core/gn/build/ohos.gni") 11 | + 12 | 13 | THIRDPARTY_PROTOBUF_SUBSYS_NAME = "thirdparty" 14 | THIRDPARTY_PROTOBUF_PART_NAME = "protobuf" 15 | @@ -50,9 +51,9 @@ ohos_shared_library("protobuf_lite") { 16 | "src/google/protobuf/stubs/time.cc", 17 | "src/google/protobuf/wire_format_lite.cc", 18 | ] 19 | - if (!is_asan && !is_debug) { 20 | - version_script = "libprotobuf_lite.map" 21 | - } 22 | + #if (!is_asan && !is_debug) { 23 | + # version_script = "libprotobuf_lite.map" 24 | + #} 25 | include_dirs = [ 26 | "src/google/protobuf/**/*.h", 27 | "src/google/protobuf/**/*.inc", 28 | @@ -74,10 +75,10 @@ ohos_shared_library("protobuf_lite") { 29 | 30 | public_configs = [ ":protobuf_config" ] 31 | install_enable = true 32 | - innerapi_tags = [ 33 | - "platformsdk_indirect", 34 | - "chipsetsdk", 35 | - ] 36 | + #innerapi_tags = [ 37 | + # "platformsdk_indirect", 38 | + # "chipsetsdk", 39 | + #] 40 | subsystem_name = "${THIRDPARTY_PROTOBUF_SUBSYS_NAME}" 41 | part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 42 | } 43 | @@ -121,7 +122,7 @@ ohos_static_library("protobuf_lite_static") { 44 | if (default_toolchain == current_toolchain) { 45 | # target build, not host build 46 | defines = [ "HAVE_HILOG" ] 47 | - external_deps = [ "hilog:libhilog" ] 48 | + #external_deps = [ "hilog:libhilog" ] 49 | } 50 | } else { 51 | defines = [ "_FILE_OFFSET_BITS_SET_LSEEK" ] 52 | @@ -142,7 +143,7 @@ ohos_static_library("protobuf_lite_static") { 53 | } 54 | public_configs = [ ":protobuf_config" ] 55 | subsystem_name = "${THIRDPARTY_PROTOBUF_SUBSYS_NAME}" 56 | - part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 57 | + #part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 58 | } 59 | 60 | ohos_shared_library("protobuf") { 61 | @@ -216,9 +217,9 @@ ohos_shared_library("protobuf") { 62 | ] 63 | 64 | deps = [ ":protobuf_lite" ] 65 | - if (!is_asan && !is_debug) { 66 | - version_script = "libprotobuf.map" 67 | - } 68 | + #if (!is_asan && !is_debug) { 69 | + # version_script = "libprotobuf.map" 70 | + #} 71 | 72 | public_configs = [ ":protobuf_config" ] 73 | install_enable = true 74 | @@ -300,7 +301,7 @@ ohos_static_library("protobuf_static") { 75 | 76 | public_configs = [ ":protobuf_config" ] 77 | subsystem_name = "${THIRDPARTY_PROTOBUF_SUBSYS_NAME}" 78 | - part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 79 | + #part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 80 | } 81 | 82 | if (current_toolchain == host_toolchain) { 83 | @@ -525,7 +526,7 @@ if (current_toolchain == host_toolchain) { 84 | 85 | public_configs = [ ":protobuf_config" ] 86 | subsystem_name = "${THIRDPARTY_PROTOBUF_SUBSYS_NAME}" 87 | - part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 88 | + #part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 89 | } 90 | } 91 | 92 | @@ -549,6 +550,6 @@ if (current_toolchain == host_toolchain) { 93 | "-Wno-deprecated-declarations", 94 | ] 95 | subsystem_name = "${THIRDPARTY_PROTOBUF_SUBSYS_NAME}" 96 | - part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 97 | + #part_name = "${THIRDPARTY_PROTOBUF_PART_NAME}" 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /loopconstruction.cpp: -------------------------------------------------------------------------------- 1 | #include "loopconstruction.h" 2 | 3 | namespace panda::compiler { 4 | 5 | void LogLoopBBs(BasicBlock* header){ 6 | ArenaVector bbs = header->GetLoop()->GetBlocks(); 7 | std::cout << "[+] loop list >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> " << std::endl; 8 | for (size_t i = 0; i < bbs.size(); i++) { 9 | panda::compiler::BasicBlock * bb = bbs[i]; 10 | std::cout << bb->GetId() << " "; 11 | if(bb->IsLoopValid() && bb->GetLoop()->IsRoot()){ 12 | std::cout << "bbi@ " << bb->GetId() << std::endl; 13 | } 14 | } 15 | 16 | std::cout << std::endl; 17 | std::cout << "[-] loop list >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> " << std::endl; 18 | } 19 | 20 | void JudgeLoopType(BasicBlock* header, std::map& loop2type, 21 | std::map &loop2exit, 22 | std::map &backedge2dowhileloop){ 23 | 24 | std::cout << "[+] judge loop type >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; 25 | if(header->GetLoop()->IsIrreducible()){ 26 | HandleError("IrreducibleLoop"); 27 | } 28 | 29 | auto &back_edges = header->GetLoop()->GetBackEdges(); 30 | int count = 0; 31 | for (auto back_edge : back_edges) { 32 | std::cout << "[*] " << count++ << " : " << back_edge->GetId() << std::endl; 33 | auto succs_size = back_edge->GetSuccsBlocks().size(); 34 | if(succs_size > 1 && back_edge->IsIfBlock()){ 35 | loop2type[header->GetLoop()] = 1; // do-whle 36 | std::cout << "do - while" << std::endl; 37 | backedge2dowhileloop[back_edge] = header->GetLoop(); 38 | 39 | if(back_edge->GetTrueSuccessor()->GetLoop() == header->GetLoop()){ 40 | loop2exit[header->GetLoop()] = back_edge->GetFalseSuccessor(); 41 | }else{ 42 | loop2exit[header->GetLoop()] = back_edge->GetTrueSuccessor(); 43 | } 44 | }else{ 45 | loop2type[header->GetLoop()] = 0; // while 46 | if(header->GetTrueSuccessor()->GetLoop() == header->GetLoop()){ 47 | loop2exit[header->GetLoop()] = header->GetFalseSuccessor(); 48 | }else{ 49 | loop2exit[header->GetLoop()] = header->GetTrueSuccessor(); 50 | } 51 | } 52 | } 53 | 54 | std::cout << "[-] judge loop type >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; 55 | 56 | //LogLoopBBs(header); 57 | } 58 | 59 | bool LoopContainBlock(Loop* loop, BasicBlock *bb){ 60 | if(std::find(loop->GetBlocks().begin(), loop->GetBlocks().end(), bb) != loop->GetBlocks().end()){ 61 | return true; 62 | } 63 | 64 | for(auto inner_loop : loop->GetInnerLoops()){ 65 | if(LoopContainBlock(inner_loop, bb)){ 66 | return true; 67 | } 68 | } 69 | 70 | return false; 71 | } 72 | 73 | 74 | 75 | void LogBackEdgeId(ArenaVector backedges){ 76 | std::cout << "backedgeid: "; 77 | for (auto it = backedges.begin(); it != backedges.end(); ++it) { 78 | std::cout << (*it)->GetId(); 79 | if (std::next(it) != backedges.end()) { 80 | std::cout << ", "; 81 | } 82 | } 83 | std::cout << std::endl; 84 | } 85 | 86 | BasicBlock* SearchPreHeader(BasicBlock* header){ 87 | for (auto pred : header->GetPredsBlocks()) { 88 | if(pred->IsLoopPreHeader()){ 89 | return pred; 90 | } 91 | } 92 | return nullptr; 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | // void HandleError(const std::string& errorMessage) { 4 | // std::cerr << "Error: " << errorMessage << std::endl; 5 | // std::exit(EXIT_FAILURE); 6 | // } 7 | 8 | 9 | std::string RemoveArgumentsOfFunc(const std::string& input) { 10 | std::string result; 11 | size_t endPos = input.find('('); 12 | if (endPos != std::string::npos) { 13 | std::string beforeParen = input.substr(0, endPos); 14 | size_t colonPos = beforeParen.find_last_not_of(':'); 15 | if (colonPos != std::string::npos) { 16 | beforeParen = beforeParen.substr(0, colonPos+1); 17 | return beforeParen; 18 | } 19 | } 20 | 21 | return input; 22 | } 23 | 24 | bool IsArray(const panda::panda_file::LiteralTag &tag) 25 | { 26 | switch (tag) { 27 | case panda::panda_file::LiteralTag::ARRAY_U1: 28 | case panda::panda_file::LiteralTag::ARRAY_U8: 29 | case panda::panda_file::LiteralTag::ARRAY_I8: 30 | case panda::panda_file::LiteralTag::ARRAY_U16: 31 | case panda::panda_file::LiteralTag::ARRAY_I16: 32 | case panda::panda_file::LiteralTag::ARRAY_U32: 33 | case panda::panda_file::LiteralTag::ARRAY_I32: 34 | case panda::panda_file::LiteralTag::ARRAY_U64: 35 | case panda::panda_file::LiteralTag::ARRAY_I64: 36 | case panda::panda_file::LiteralTag::ARRAY_F32: 37 | case panda::panda_file::LiteralTag::ARRAY_F64: 38 | case panda::panda_file::LiteralTag::ARRAY_STRING: 39 | return true; 40 | default: 41 | return false; 42 | } 43 | } 44 | 45 | std::optional> GetLiteralArrayByOffset(panda::pandasm::Program* program, uint32_t offset){ 46 | std::vector res; 47 | std::stringstream hexStream; 48 | hexStream << "0x" << std::hex << offset; 49 | std::string offsetString = hexStream.str(); 50 | 51 | for (const auto &[key, lit_array] : program->literalarray_table) { 52 | const auto &tag = lit_array.literals_[0].tag_; 53 | 54 | if (key.find(offsetString) == std::string::npos || IsArray(tag)) { 55 | continue; 56 | } 57 | 58 | for (size_t i = 0; i < lit_array.literals_.size(); i++) { 59 | const auto &tag = lit_array.literals_[i].tag_; 60 | const auto &val = lit_array.literals_[i].value_; 61 | if(tag == panda::panda_file::LiteralTag::METHOD || tag == panda::panda_file::LiteralTag::GETTER || 62 | tag == panda::panda_file::LiteralTag::SETTER || tag == panda::panda_file::LiteralTag::GENERATORMETHOD){ 63 | res.push_back(std::get(val)); 64 | } 65 | } 66 | return res; 67 | } 68 | 69 | return std::nullopt; 70 | } 71 | 72 | 73 | std::optional FindKeyByValue(const std::map& myMap, const uint32_t& value) { 74 | for (const auto& pair : myMap) { 75 | if (pair.second == value) { 76 | return pair.first; 77 | } 78 | } 79 | return std::nullopt; 80 | } 81 | 82 | 83 | uint32_t ParseHexFromKey(const std::string& key) { 84 | std::istringstream iss(key); 85 | std::string temp; 86 | std::string hexString; 87 | 88 | while (iss >> temp) { 89 | if (temp.find("0x") == 0 || temp.find("0X") == 0) { 90 | hexString = temp; 91 | break; 92 | } 93 | } 94 | 95 | uint32_t hexNumber = 0; 96 | if (!hexString.empty()) { 97 | std::istringstream(hexString) >> std::hex >> hexNumber; 98 | } 99 | 100 | return hexNumber; 101 | } -------------------------------------------------------------------------------- /autotests/count_json_members.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | from pathlib import Path 4 | import sys 5 | 6 | # --- Configuration --- 7 | # Default directory for categorized outputs 8 | DEFAULT_CATEGORY_DIR = "status_outputs" 9 | # Name of the global result file located within the default directory 10 | DEFAULT_GLOBAL_RESULT_FILE_NAME = "res.json" 11 | 12 | def count_members_in_json_file(filepath): 13 | """ 14 | Reads a JSON file and counts the number of members (list items or dict keys). 15 | """ 16 | try: 17 | with open(filepath, 'r', encoding='utf-8') as f: 18 | data = json.load(f) 19 | if isinstance(data, list) or isinstance(data, dict): 20 | count = len(data) 21 | return count, "valid" 22 | else: 23 | return 1, type(data).__name__ 24 | 25 | except (FileNotFoundError, json.JSONDecodeError, Exception) as e: 26 | # print(f"Error reading {filepath}: {e}") # Keep quiet for cleaner output 27 | return 0, "N/A" 28 | 29 | def main(): 30 | parser = argparse.ArgumentParser(description="Read JSON files in a directory and count members/items, calculating percentages.") 31 | 32 | # Directory argument, optional with default value 33 | parser.add_argument("-D", "--directory", type=str, default=DEFAULT_CATEGORY_DIR, 34 | help=f"The directory containing all JSON files (including res.json) (default: '{DEFAULT_CATEGORY_DIR}').") 35 | 36 | # Global file name argument for overriding the default name 37 | parser.add_argument("-G", "--global_file_name", type=str, default=DEFAULT_GLOBAL_RESULT_FILE_NAME, 38 | help=f"The name of the global JSON file (must be inside the directory) (default: '{DEFAULT_GLOBAL_RESULT_FILE_NAME}').") 39 | 40 | args = parser.parse_args() 41 | 42 | input_dir = Path(args.directory) 43 | global_file_path = input_dir / args.global_file_name # Construct full path 44 | 45 | if not input_dir.is_dir(): 46 | print(f"Error: '{args.directory}' is not a valid directory.") 47 | sys.exit(1) 48 | if not global_file_path.is_file(): 49 | print(f"Error: Global result file not found at '{global_file_path}'. Please ensure '{args.global_file_name}' exists within the '{args.directory}' directory.") 50 | sys.exit(1) 51 | 52 | # 1. Get the total count 53 | total_count, _ = count_members_in_json_file(global_file_path) 54 | 55 | if total_count == 0: 56 | print("Error: Global result file is empty, cannot calculate proportions.") 57 | sys.exit(1) 58 | 59 | print("-" * 45) 60 | print(f"Total file count (from {global_file_path.name}): {total_count}") 61 | print(f"Scanning directory: {input_dir.resolve()}") 62 | print("-" * 45) 63 | 64 | # 2. Scan categorized JSON files and count members 65 | # Find all JSON files in the directory 66 | json_files = sorted(list(input_dir.glob('*.json'))) 67 | 68 | if not json_files: 69 | print("No categorized JSON files found in the specified directory.") 70 | return 71 | 72 | processed_count = 0 73 | 74 | print("File Name | Count | Proportion") 75 | print("-" * 45) 76 | for file_path in json_files: 77 | # Exclude the global file itself from the categorized list 78 | if file_path.name == args.global_file_name: 79 | continue 80 | 81 | count, data_type = count_members_in_json_file(file_path) 82 | if count > 0: 83 | percentage = (count / total_count) * 100 84 | # Use formatted output to align columns 85 | print(f"{file_path.name:<20} | {count:^4} | {percentage:8.2f}%") 86 | processed_count += count 87 | 88 | print("-" * 45) 89 | print(f"Processed category total: {processed_count} (Should ideally equal total count {total_count})") 90 | if processed_count != total_count: 91 | print(f"Warning: Total counts do not match, there might be uncategorized records or JSON parsing errors.") 92 | 93 | 94 | if __name__ == "__main__": 95 | main() 96 | -------------------------------------------------------------------------------- /fundepscan.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_FUNDEPSCAN 2 | #define DECOMPILER_FUNDEPSCAN 3 | 4 | #include "base.h" 5 | 6 | namespace panda::bytecodeopt { 7 | 8 | using compiler::BasicBlock; 9 | using compiler::Inst; 10 | using compiler::Opcode; 11 | 12 | class FunDepScan : public compiler::Optimization, public compiler::GraphVisitor { 13 | public: 14 | explicit FunDepScan(compiler::Graph *graph, const BytecodeOptIrInterface *iface, panda::pandasm::Program* program, 15 | panda::disasm::Disassembler& disasm, uint32_t methodoffset, 16 | std::vector>* depedges, 17 | std::map> *class2memberfuns, 18 | std::map>>* method2lexicalmap, 19 | std::set* memberfuncs, 20 | std::map *raw2newname, 21 | std::map *methodname2offset 22 | ) 23 | : compiler::Optimization(graph), ir_interface_(iface), program_(program), disasm_(disasm), methodoffset_(methodoffset), 24 | depedges_(depedges), class2memberfuns_(class2memberfuns), method2lexicalmap_(method2lexicalmap), 25 | memberfuncs_(memberfuncs), raw2newname_(raw2newname), methodname2offset_(methodname2offset) 26 | { 27 | this->current_function_initializer = 0; 28 | this->current_constructor_offset = 0; 29 | } 30 | 31 | ~FunDepScan() override = default; 32 | bool RunImpl() override; 33 | 34 | const char *GetPassName() const override 35 | { 36 | return "FunDepScan"; 37 | } 38 | 39 | const ArenaVector &GetBlocksToVisit() const override 40 | { 41 | return GetGraph()->GetBlocksRPO(); 42 | } 43 | 44 | void UpdateMemberDepConstructor(){ 45 | // method define class > instance_initializer > member functions 46 | 47 | uint32_t last_member = 0; 48 | for(const auto& constructor_offset : this->inserted_construct_order_){ 49 | if(this->class2memberfuns_->find(constructor_offset) == this->class2memberfuns_->end()){ 50 | continue; 51 | } 52 | 53 | auto member_funcs = (*this->class2memberfuns_)[constructor_offset]; 54 | this->memberfuncs_->insert(constructor_offset); 55 | 56 | uint32_t function_initializer = 0; 57 | if(this->construct2initializer_.find(constructor_offset) != this->construct2initializer_.end()){ 58 | function_initializer = this->construct2initializer_[constructor_offset]; 59 | } 60 | 61 | if(function_initializer && last_member){ 62 | this->depedges_->push_back(std::make_pair(last_member, function_initializer)); 63 | } 64 | 65 | for (const auto& memeber_offset : member_funcs) { 66 | this->memberfuncs_->insert(memeber_offset); 67 | last_member = memeber_offset; 68 | if(function_initializer && function_initializer != memeber_offset){ 69 | this->depedges_->push_back(std::make_pair(function_initializer, memeber_offset)); 70 | } 71 | } 72 | } 73 | } 74 | 75 | static void VisitIntrinsic(GraphVisitor *visitor, Inst *inst_base); 76 | static void VisitEcma(panda::compiler::GraphVisitor *visitor, Inst *inst_base); 77 | 78 | #include "compiler/optimizer/ir/visitor.inc" 79 | 80 | const BytecodeOptIrInterface *ir_interface_; 81 | panda::pandasm::Program* program_; 82 | [[maybe_unused]] panda::disasm::Disassembler& disasm_; 83 | uint32_t methodoffset_; 84 | 85 | std::vector>* depedges_; // left depends on right 86 | std::map> *class2memberfuns_; 87 | 88 | std::map>> *method2lexicalmap_; 89 | 90 | std::set* memberfuncs_; 91 | 92 | [[maybe_unused]] std::map *raw2newname_; 93 | 94 | std::map *methodname2offset_; 95 | 96 | std::map construct2initializer_; 97 | 98 | std::vector inserted_construct_order_; 99 | 100 | uint32_t current_constructor_offset; 101 | uint32_t current_function_initializer; 102 | 103 | }; 104 | 105 | } 106 | #endif 107 | -------------------------------------------------------------------------------- /tests/6.loop.ts: -------------------------------------------------------------------------------- 1 | // #22. for 2 | // const array = [10, 20, 30]; 3 | // var x; 4 | // for (const value of array.values()) { 5 | // x = console.log(value); 6 | // } 7 | 8 | // const array = [10, 20, 30]; 9 | // var x; 10 | // for (const value of array.values()) { 11 | // x = console.log(value); 12 | // } 13 | 14 | // #22. for - normal 15 | // var x = 1; 16 | // for (var i = 0; i < 5; i++) { 17 | // x = i; 18 | // } 19 | // x = 10; 20 | 21 | // #22. for - continue 22 | // var x = 0; 23 | // for (var i = 0; i < 5; i++) { 24 | // if (i === 2) { 25 | // x = 1; 26 | // continue; 27 | // } 28 | // x = 2; 29 | // } 30 | // x = 3; 31 | 32 | // #22. for - break 33 | // var x = 0; 34 | // for (var i = 0; i < 10; i++) { 35 | // x = 1; 36 | // if (i === 5) { 37 | // x = 2; 38 | // break; 39 | // }else{ 40 | // x = 4; 41 | // } 42 | // x = 3; 43 | // } 44 | // x = 5; 45 | 46 | 47 | // #22. for - return 48 | // function findNumber() { 49 | // var x = 5; 50 | // var i = 0; 51 | // for (i = 0; i < 10; i++) { 52 | // if (i = x) { 53 | // return i; 54 | // } 55 | // } 56 | // return -1; 57 | // } 58 | 59 | 60 | // #22. for - break-throw 61 | // for (var i = 0; i < 10; i++) { 62 | // if (i === 5) { 63 | // throw new Error('exit'); 64 | // } 65 | // } 66 | 67 | // #22. for - break-to-label 68 | // loop1:{ 69 | 70 | // loop2:{ 71 | // var x = 0; 72 | // console.log("hello"); 73 | // for (let i = 0; i < 5; i++) { 74 | // if (i === 3) { 75 | // x = 1; 76 | // console.log(x); 77 | // break loop1; 78 | // } 79 | // x = 2; 80 | // } 81 | // } 82 | // } 83 | 84 | 85 | 86 | 87 | // # 22. while - normal 88 | // var x = 0; 89 | // var i = 0; 90 | // while (i < 5) { 91 | // x = i; 92 | // i = i + 1; 93 | // } 94 | // x = 10; 95 | 96 | // # 22. while - continue 97 | // var x = 0; 98 | // var i = 0; 99 | // while (i < 5) { 100 | // i++; 101 | // if (i === 3) { 102 | // x = i; 103 | // continue; 104 | // } 105 | // x = 4; 106 | // } 107 | // x = 5; 108 | 109 | // # 22. while - break 110 | // var x = 0 111 | // var i = 0; 112 | // while (true) { 113 | // i++; 114 | // if (i === 5) { 115 | // x = i; 116 | // break; 117 | // } 118 | // x = 1; 119 | // } 120 | // x = 3; 121 | 122 | 123 | // # 22. while - return 124 | // function processData() { 125 | // var i = 0; 126 | // var x = 0; 127 | // while (i < 10) { 128 | // x = i + 1; 129 | // if (i === 5) { 130 | // x = 2; 131 | // return; 132 | // } 133 | // i++; 134 | // } 135 | // x = 7; 136 | // } 137 | 138 | // # 22. while - throw 139 | // var i = 0; 140 | // var x = 0; 141 | // while (i < 10) { 142 | // x = 1; 143 | // if (i === 5) { 144 | // x = 2; 145 | // throw new Error('1'); 146 | // } 147 | // i++; 148 | // x = 3; 149 | // } 150 | // x = 4; 151 | 152 | //# 22. dowhile - normal 153 | // var i = 0; 154 | // var x = 1; 155 | // do { 156 | // x = 1 157 | // i++; 158 | // } while (i < 5); 159 | // x = 2; 160 | 161 | //# 22. dowhile - continue 162 | // var i = 0; 163 | // var x = 1; 164 | // do { 165 | // i++; 166 | // if (i === 3) { 167 | // x = 2; 168 | // continue; 169 | // } 170 | // x = i; 171 | // } while (i < 5); 172 | // x = 3; 173 | 174 | // # 22. dowhile - break 175 | // var i = 0; 176 | // var x = 1; 177 | // do { 178 | // i++; 179 | // x = 2; 180 | // if (x >= 8) { 181 | // x = 3; 182 | // break; 183 | // } 184 | // } while (i < 5); 185 | // x = 4; 186 | 187 | // # 22. dowhile - return 188 | // function example2() { 189 | // var i = 0; 190 | // var x = 1; 191 | // do { 192 | // i++; 193 | // x = i * 10; 194 | 195 | // if (x >= 30) { 196 | // x = 888; 197 | // return; 198 | // } 199 | // } while (i < 5); 200 | 201 | // x = 2; 202 | // return; 203 | // } 204 | 205 | // # 22. dowhile - throw 206 | // var i = 0; 207 | // var x = 1; 208 | // do { 209 | // i++; 210 | // x = i; 211 | 212 | // if (i === 3) { 213 | // x = 99; 214 | // throw new Error("z"); 215 | // } 216 | // } while (i < 5); 217 | // x = 2; 218 | 219 | // while-catch 220 | // const list = [] 221 | // for(let x of list) { 222 | // console.log("hi"); 223 | // } -------------------------------------------------------------------------------- /scripts/draw_cfg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -- coding: utf-8 -- 3 | 4 | from typing import List 5 | import graphviz as gv 6 | import sys 7 | import os 8 | import argparse 9 | 10 | 11 | class BasicBlock: 12 | def __init__(self, ident: int) -> None: 13 | self.id = ident 14 | self.insts = [] 15 | self.preds = [] 16 | self.succs = [] 17 | self.props = [] 18 | 19 | def text(self, no_insts=False) -> str: 20 | s = 'BB ' + str(self.id) + '\n' 21 | s += 'props: ' 22 | for i, prop in enumerate(self.props): 23 | if i > 0: 24 | s += ', ' 25 | s += prop 26 | s += '\n' 27 | 28 | if not no_insts: 29 | for inst in self.insts: 30 | s += inst + '\n' 31 | return s 32 | 33 | 34 | class Function: 35 | def __init__(self, method: str, blocks: List[BasicBlock]) -> None: 36 | self.method = method 37 | self.blocks = blocks 38 | 39 | 40 | class GraphDumpParser: 41 | def __init__(self) -> None: 42 | self.method = None 43 | self.block = None 44 | self.blocks = [] 45 | self.functions = [] 46 | 47 | def finish_block(self): 48 | if self.block: 49 | self.blocks.append(self.block) 50 | self.block = None 51 | 52 | def finish_function(self): 53 | self.finish_block() 54 | if self.method: 55 | self.functions.append(Function(self.method, self.blocks)) 56 | self.blocks = [] 57 | 58 | def begin_block(self, line: str): 59 | self.finish_block() 60 | 61 | preds_start = line.find('preds:') 62 | block_id = int(line[len('BB'):preds_start].strip()) 63 | self.block = BasicBlock(block_id) 64 | if preds_start != -1: 65 | self.parse_block_preds(line, preds_start) 66 | 67 | def begin_function(self, line: str): 68 | self.finish_function() 69 | self.method = line[len('method:'):].strip() 70 | 71 | def parse_block_preds(self, line: str, preds_start: int): 72 | preds = line[preds_start+len('preds:'):].strip().strip('[]') 73 | for pred in preds.split(','): 74 | pred = pred.strip() 75 | self.block.preds.append(int(pred[len('bb'):].strip())) 76 | 77 | def parse_block_props(self, line: str): 78 | for s in line[len('prop:'):].strip().split(','): 79 | s = s.strip() 80 | if not s.startswith('bc'): 81 | self.block.props.append(s) 82 | 83 | def parse_block_succs(self, line: str): 84 | succs = line[len('succs:'):].strip().strip('[]') 85 | for succ in succs.split(','): 86 | succ = succ.strip() 87 | self.block.succs.append(int(succ[len('bb'):].strip())) 88 | self.finish_block() 89 | 90 | def parse(self, lines: List[str]) -> List[Function]: 91 | for line in lines: 92 | if line.startswith('Method:'): 93 | self.begin_function(line) 94 | elif line.startswith('BB'): 95 | self.begin_block(line) 96 | elif self.block: 97 | if line.startswith('prop:'): 98 | self.parse_block_props(line) 99 | elif line.startswith('succs:'): 100 | self.parse_block_succs(line) 101 | else: 102 | self.block.insts.append(line) 103 | self.finish_function() 104 | return self.functions 105 | 106 | 107 | def draw_function(function: Function, out_dir=None, no_insts=False): 108 | dot = gv.Digraph(format='png') 109 | for block in function.blocks: 110 | dot.node(str(block.id), block.text(no_insts), shape='box') 111 | for block in function.blocks: 112 | for succ in block.succs: 113 | dot.edge(str(block.id), str(succ)) 114 | basename = 'cfg_' + function.method 115 | dotfile_path = os.path.join(out_dir, basename) 116 | dot.render(basename, out_dir, format="png") 117 | os.rename(dotfile_path, dotfile_path + '.dot') 118 | 119 | 120 | def main(): 121 | parser = argparse.ArgumentParser(description="A tool for drawing CFGs by reading ir dump from stdin") 122 | parser.add_argument("-i", "--input", type=str, default="input.ir", help="the file containing the IR dump (default: 'input.ir')") 123 | parser.add_argument("--no-insts", action="store_true", help="drawing without IR instructions") 124 | parser.add_argument("-o", "--output", type=str, default="./out", help="output directory, default to './out'") 125 | args = parser.parse_args() 126 | 127 | with open(args.input, 'r') as file: 128 | lines = file.readlines() 129 | 130 | functions = GraphDumpParser().parse(lines) 131 | for function in functions: 132 | draw_function(function, args.output, no_insts=args.no_insts) 133 | 134 | 135 | if __name__ == "__main__": 136 | main() 137 | -------------------------------------------------------------------------------- /fundepscan.cpp: -------------------------------------------------------------------------------- 1 | #include "fundepscan.h" 2 | 3 | namespace panda::bytecodeopt { 4 | 5 | bool FunDepScan::RunImpl(){ 6 | for (auto *bb : GetGraph()->GetBlocksLinearOrder()) { 7 | for (const auto &inst : bb->AllInsts()) { 8 | VisitInstruction(inst); 9 | } 10 | } 11 | 12 | this->UpdateMemberDepConstructor(); 13 | return true; 14 | } 15 | 16 | void FunDepScan::VisitIntrinsic(GraphVisitor *visitor, Inst *inst_base) 17 | { 18 | ASSERT(inst_base->IsIntrinsic()); 19 | VisitEcma(visitor, inst_base); 20 | } 21 | 22 | void FunDepScan::VisitEcma(panda::compiler::GraphVisitor *visitor, Inst *inst_base){ 23 | 24 | ASSERT(inst_base->IsIntrinsic()); 25 | auto inst = inst_base->CastToIntrinsic(); 26 | auto enc = static_cast(visitor); 27 | switch(inst->GetIntrinsicId()){ 28 | case compiler::RuntimeInterface::IntrinsicId::DEFINEMETHOD_IMM8_ID16_IMM8: 29 | case compiler::RuntimeInterface::IntrinsicId::DEFINEMETHOD_IMM16_ID16_IMM8: 30 | case compiler::RuntimeInterface::IntrinsicId::DEFINEFUNC_IMM8_ID16_IMM8: 31 | case compiler::RuntimeInterface::IntrinsicId::DEFINEFUNC_IMM16_ID16_IMM8:{ 32 | auto methodoffset = static_cast(inst->GetImms()[1]); 33 | enc->depedges_->push_back(std::make_pair(enc->methodoffset_, methodoffset)); 34 | 35 | auto method_name = enc->ir_interface_->GetMethodIdByOffset(methodoffset); 36 | if(inst->GetIntrinsicId() == compiler::RuntimeInterface::IntrinsicId::DEFINEMETHOD_IMM8_ID16_IMM8 || 37 | inst->GetIntrinsicId() == compiler::RuntimeInterface::IntrinsicId::DEFINEMETHOD_IMM16_ID16_IMM8){ 38 | 39 | if(method_name.find("instance_initializer") != std::string::npos){ 40 | (*enc->class2memberfuns_)[enc->current_constructor_offset].insert(methodoffset); 41 | 42 | if(enc->current_constructor_offset){ 43 | std::cout << "set construct2initializer: " << enc->current_constructor_offset << " : " << methodoffset << std::endl; 44 | enc->construct2initializer_[enc->current_constructor_offset] = methodoffset; 45 | }else{ 46 | HandleError("#DEFINEMETHOD: find current_constructor_offset error"); 47 | } 48 | 49 | } 50 | } 51 | break; 52 | } 53 | 54 | case compiler::RuntimeInterface::IntrinsicId::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: 55 | case compiler::RuntimeInterface::IntrinsicId::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: 56 | case compiler::RuntimeInterface::IntrinsicId::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: 57 | { 58 | auto constructor_offset = static_cast(inst->GetImms()[1]); 59 | enc->current_constructor_offset = constructor_offset; 60 | 61 | enc->inserted_construct_order_.push_back(enc->current_constructor_offset); 62 | 63 | (*enc->class2memberfuns_)[constructor_offset].insert(constructor_offset); 64 | 65 | // case: not include instance_initializer 66 | // enc->depedges_->push_back(std::make_pair(enc->methodoffset_, constructor_offset)); 67 | 68 | auto literalarray_offset = static_cast(inst->GetImms()[2]); 69 | auto member_functions = GetLiteralArrayByOffset(enc->program_, literalarray_offset); 70 | if(member_functions){ 71 | for(auto const& member_function : *member_functions){ 72 | if (enc->methodname2offset_->find(member_function) != enc->methodname2offset_->end()) { 73 | auto memeber_offset = (*enc->methodname2offset_)[member_function]; 74 | (*enc->class2memberfuns_)[constructor_offset].insert(memeber_offset); 75 | }else{ 76 | HandleError("#function dep scan: DEFINECLASSWITHBUFFER"); 77 | } 78 | } 79 | } 80 | break; 81 | } 82 | 83 | case compiler::RuntimeInterface::IntrinsicId::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16:{ 84 | auto ir_id0 = static_cast(inst->GetImms()[1]); 85 | auto member_functions = GetLiteralArrayByOffset(enc->program_, ir_id0); 86 | if(member_functions){ 87 | for(const auto& member_function : *member_functions){ 88 | auto memeber_offset = (*enc->methodname2offset_)[member_function]; 89 | (*enc->class2memberfuns_)[enc->current_constructor_offset].insert(memeber_offset); 90 | 91 | // case: not include instance_initializer 92 | //enc->depedges_->push_back(std::make_pair(enc->methodoffset_, memeber_offset)); 93 | } 94 | }else{ 95 | HandleError("#function dep scan: CALLRUNTIME_CREATEPRIVATEPROPERTY"); 96 | } 97 | break; 98 | } 99 | 100 | case compiler::RuntimeInterface::IntrinsicId::CALLRUNTIME_DEFINEPRIVATEPROPERTY_PREF_IMM8_IMM16_IMM16_V8:{ 101 | auto tier = static_cast(inst->GetImms()[1]); 102 | auto index = static_cast(inst->GetImms()[2]); 103 | (*enc->method2lexicalmap_)[enc->methodoffset_][tier].insert(index); 104 | 105 | break; 106 | } 107 | 108 | default:; 109 | } 110 | } 111 | 112 | }; 113 | -------------------------------------------------------------------------------- /astgen_auxiins.cpp: -------------------------------------------------------------------------------- 1 | void AstGen::VisitPhi(GraphVisitor* v, Inst* inst_base) { 2 | std::cout << "[+] VisitPhi >>>>>>>>>>>>>>>>>" << std::endl; 3 | pandasm::Ins ins; 4 | auto enc = static_cast(v); 5 | auto inst = inst_base->CastToPhi(); 6 | ArenaVector arguments(enc->parser_program_->Allocator()->Adapter()); 7 | 8 | auto dst_reg_identifier = enc->GetIdentifierByReg(inst->GetId()); 9 | enc->SetExpressionByRegister(inst, inst->GetDstReg(), dst_reg_identifier); 10 | 11 | for (size_t i = 0; i < inst->GetInputsCount(); i++) { 12 | auto bb = inst->GetPhiInputBb(i); 13 | auto sourceexpression = *enc->GetExpressionByRegIndex(inst, i); 14 | auto assignexpression = AllocNode(enc, 15 | dst_reg_identifier, 16 | sourceexpression, 17 | es2panda::lexer::TokenType::PUNCTUATOR_SUBSTITUTION 18 | ); 19 | auto assignstatement = AllocNode(enc, assignexpression); 20 | 21 | if(std::find(enc->visited.begin(), enc->visited.end(), bb) != enc->visited.end()){ 22 | enc->AddInstAst2BlockStatemntByBlock(bb, assignstatement); 23 | }else{ 24 | if(enc->phiref2pendingredundant.find(bb) != enc->phiref2pendingredundant.end()){ 25 | auto found_block_statement = enc->phiref2pendingredundant[bb]; 26 | const auto &statements = found_block_statement->Statements(); 27 | found_block_statement->AddStatementAtPos(statements.size(), assignstatement); 28 | }else{ 29 | ArenaVector statements(enc->parser_program_->Allocator()->Adapter()); 30 | auto new_block_statement = AllocNode(enc, nullptr, std::move(statements)); 31 | new_block_statement->AddStatementAtPos(statements.size(), assignstatement); 32 | } 33 | } 34 | } 35 | 36 | std::cout << "[-] VisitPhi <<<<<<<<<<<<<<<" << std::endl; 37 | } 38 | 39 | void AstGen::VisitSaveState(GraphVisitor* v, Inst* inst_base) { 40 | std::cout << "[+] VisitSaveState >>>>>>>>>>>>>>>>>" << std::endl; 41 | std::cout << "[-] VisitSaveState >>>>>>>>>>>>>>>>>" << std::endl; 42 | } 43 | void AstGen::VisitParameter(GraphVisitor* v, Inst* inst_base) { 44 | std::cout << "[+] VisitParameter >>>>>>>>>>>>>>>>>" << std::endl; 45 | auto enc = static_cast(v); 46 | auto inst = inst_base->CastToParameter(); 47 | 48 | panda::es2panda::ir::Expression* arg = enc->getParameterName(inst->GetArgNumber()); 49 | enc->SetExpressionByRegister(inst, inst->GetDstReg(), arg); 50 | std::cout << "[-] VisitParameter >>>>>>>>>>>>>>>>>" << std::endl; 51 | } 52 | 53 | void AstGen::VisitTry(GraphVisitor* v, Inst* inst_base) { 54 | std::cout << "[+] VisitTry >>>>>>>>>>>>>>>>>" << std::endl; 55 | pandasm::Ins ins; 56 | auto enc = static_cast(v); 57 | auto inst = inst_base->CastToTry(); 58 | 59 | // find tryblock 60 | BasicBlock* tryblock = nullptr; 61 | if(inst->GetBasicBlock()->GetSuccessor(0)->IsCatchBegin()){ 62 | tryblock = inst->GetBasicBlock()->GetSuccessor(1); 63 | }else if(inst->GetBasicBlock()->GetSuccessor(1)->IsCatchBegin()){ 64 | tryblock = inst->GetBasicBlock()->GetSuccessor(0); 65 | }else{ 66 | HandleError("can't handle this case in visitTry for finding try block"); 67 | } 68 | 69 | enc->specialblockid.insert(tryblock->GetId()); 70 | 71 | panda::es2panda::ir::BlockStatement* tryblock_statement = enc->GetBlockStatementById(tryblock); 72 | 73 | if(inst->GetBasicBlock()->GetTryId() != panda::compiler::INVALID_ID){ 74 | enc->tyrid2block[inst->GetBasicBlock()->GetTryId()] = tryblock_statement; 75 | } 76 | 77 | 78 | /// find case block 79 | auto type_ids = inst->GetCatchTypeIds(); 80 | auto catch_indexes = inst->GetCatchEdgeIndexes(); 81 | 82 | panda::es2panda::ir::CatchClause *catchClause = nullptr; 83 | for (size_t idx = 0; idx < type_ids->size(); idx++) { 84 | auto succ = inst->GetBasicBlock()->GetSuccessor(catch_indexes->at(idx)); 85 | 86 | while (!succ->IsCatchBegin()) { 87 | succ = succ->GetSuccessor(0); 88 | } 89 | 90 | enc->specialblockid.insert(succ->GetId()); 91 | auto catch_block = enc->GetBlockStatementById(succ); 92 | 93 | panda::es2panda::ir::Expression *param = enc->constant_catcherror; 94 | 95 | 96 | catchClause = AllocNode(enc, nullptr, param, catch_block); 97 | enc->tyrid2catchclause[inst->GetBasicBlock()->GetTryId()] = catchClause; 98 | } 99 | 100 | 101 | if(inst->GetBasicBlock()->GetPredsBlocks().size() > 2){ 102 | HandleError("analysis try-catch error for more than one predecessor"); 103 | } 104 | 105 | // create null finally case 106 | ArenaVector finally_statements(enc->parser_program_->Allocator()->Adapter()); 107 | auto finnalyClause = AllocNode(enc, nullptr, std::move(finally_statements)); 108 | 109 | // create try-catch statement 110 | enc->GetBlockStatementById(inst->GetBasicBlock()); 111 | 112 | auto tryStatement = AllocNode(enc, tryblock_statement, catchClause, finnalyClause); 113 | enc->tyridtrystatement[inst->GetBasicBlock()->GetTryId()] = tryStatement; 114 | 115 | enc->AddInstAst2BlockStatemntByInst(inst_base, tryStatement); 116 | 117 | std::cout << "[-] VisitTry >>>>>>>>>>>>>>>>>" << std::endl; 118 | 119 | } 120 | -------------------------------------------------------------------------------- /ast.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_AST 2 | #define DECOMPILER_AST 3 | 4 | #include "../ets_frontend/es2panda/es2panda.h" 5 | #include "../ets_frontend/es2panda/parser/program/program.h" 6 | 7 | ///////////////////////////////////////////////////// 8 | #include "../ets_frontend/es2panda/ir/base/catchClause.h" 9 | #include "../ets_frontend/es2panda/ir/base/classStaticBlock.h" 10 | #include "../ets_frontend/es2panda/ir/base/decorator.h" 11 | #include "../ets_frontend/es2panda/ir/base/scriptFunction.h" 12 | 13 | 14 | #include "../ets_frontend/es2panda/ir/expressions/assignmentExpression.h" 15 | #include "../ets_frontend/es2panda/ir/expressions/binaryExpression.h" 16 | #include "../ets_frontend/es2panda/ir/expressions/callExpression.h" 17 | #include "../ets_frontend/es2panda/ir/expressions/classExpression.h" 18 | #include "../ets_frontend/es2panda/ir/expressions/functionExpression.h" 19 | #include "../ets_frontend/es2panda/ir/expressions/memberExpression.h" 20 | #include "../ets_frontend/es2panda/ir/expressions/objectExpression.h" 21 | #include "../ets_frontend/es2panda/ir/expressions/sequenceExpression.h" 22 | #include "../ets_frontend/es2panda/ir/expressions/templateLiteral.h" 23 | #include "../ets_frontend/es2panda/ir/expressions/thisExpression.h" 24 | #include "../ets_frontend/es2panda/ir/expressions/unaryExpression.h" 25 | #include "../ets_frontend/es2panda/ir/expressions/arrayExpression.h" 26 | 27 | 28 | #include "../ets_frontend/es2panda/ir/base/property.h" 29 | #include "../ets_frontend/es2panda/ir/base/spreadElement.h" 30 | 31 | 32 | #include "../ets_frontend/es2panda/ir/expressions/literals/bigIntLiteral.h" 33 | #include "../ets_frontend/es2panda/ir/expressions/literals/numberLiteral.h" 34 | #include "../ets_frontend/es2panda/ir/expressions/literals/stringLiteral.h" 35 | #include "../ets_frontend/es2panda/ir/expressions/literals/booleanLiteral.h" 36 | #include "../ets_frontend/es2panda/ir/expressions/literals/nullLiteral.h" 37 | #include "../ets_frontend/es2panda/ir/expressions/literals/regExpLiteral.h" 38 | #include "../ets_frontend/es2panda/ir/expressions/literals/taggedLiteral.h" 39 | 40 | 41 | #include "../ets_frontend/es2panda/ir/expressions/memberExpression.h" 42 | #include "../ets_frontend/es2panda/ir/expressions/objectExpression.h" 43 | #include "../ets_frontend/es2panda/ir/expressions/sequenceExpression.h" 44 | #include "../ets_frontend/es2panda/ir/expressions/templateLiteral.h" 45 | #include "../ets_frontend/es2panda/ir/expressions/thisExpression.h" 46 | 47 | #include "../ets_frontend/es2panda/ir/expressions/newExpression.h" 48 | #include "../ets_frontend/es2panda/ir/expressions/awaitExpression.h" 49 | #include "../ets_frontend/es2panda/ir/expressions/yieldExpression.h" 50 | 51 | 52 | #include "../ets_frontend/es2panda/ir/module/exportDefaultDeclaration.h" 53 | #include "../ets_frontend/es2panda/ir/module/exportNamedDeclaration.h" 54 | 55 | #include "../ets_frontend/es2panda/ir/statements/blockStatement.h" 56 | #include "../ets_frontend/es2panda/ir/statements/classDeclaration.h" 57 | #include "../ets_frontend/es2panda/ir/statements/expressionStatement.h" 58 | #include "../ets_frontend/es2panda/ir/statements/forInStatement.h" 59 | #include "../ets_frontend/es2panda/ir/statements/forOfStatement.h" 60 | #include "../ets_frontend/es2panda/ir/statements/forUpdateStatement.h" 61 | #include "../ets_frontend/es2panda/ir/statements/functionDeclaration.h" 62 | #include "../ets_frontend/es2panda/ir/statements/returnStatement.h" 63 | #include "../ets_frontend/es2panda/ir/statements/switchStatement.h" 64 | #include "../ets_frontend/es2panda/ir/statements/variableDeclaration.h" 65 | #include "../ets_frontend/es2panda/ir/statements/variableDeclarator.h" 66 | #include "../ets_frontend/es2panda/ir/statements/debuggerStatement.h" 67 | #include "../ets_frontend/es2panda/ir/statements/ifStatement.h" 68 | #include "../ets_frontend/es2panda/ir/statements/tryStatement.h" 69 | #include "../ets_frontend/es2panda/ir/statements/throwStatement.h" 70 | 71 | 72 | #include "../ets_frontend/es2panda/ir/statements/whileStatement.h" 73 | #include "../ets_frontend/es2panda/ir/statements/doWhileStatement.h" 74 | 75 | #include "../ets_frontend/es2panda/ir/statements/breakStatement.h" 76 | 77 | #include "../ets_frontend/es2panda/ir/ts/tsConstructorType.h" 78 | #include "../ets_frontend/es2panda/ir/ts/tsEnumDeclaration.h" 79 | #include "../ets_frontend/es2panda/ir/ts/tsEnumMember.h" 80 | #include "../ets_frontend/es2panda/ir/ts/tsFunctionType.h" 81 | #include "../ets_frontend/es2panda/ir/ts/tsImportEqualsDeclaration.h" 82 | #include "../ets_frontend/es2panda/ir/ts/tsInterfaceDeclaration.h" 83 | #include "../ets_frontend/es2panda/ir/ts/tsMethodSignature.h" 84 | #include "../ets_frontend/es2panda/ir/ts/tsModuleBlock.h" 85 | #include "../ets_frontend/es2panda/ir/ts/tsModuleDeclaration.h" 86 | #include "../ets_frontend/es2panda/ir/ts/tsParameterProperty.h" 87 | #include "../ets_frontend/es2panda/ir/ts/tsPrivateIdentifier.h" 88 | #include "../ets_frontend/es2panda/ir/ts/tsQualifiedName.h" 89 | #include "../ets_frontend/es2panda/ir/ts/tsSignatureDeclaration.h" 90 | #include "../ets_frontend/es2panda/ir/ts/tsTypeParameterDeclaration.h" 91 | 92 | #include "../ets_frontend/es2panda/ir/module/importSpecifier.h" 93 | #include "../ets_frontend/es2panda/ir/module/importDeclaration.h" 94 | #include "../ets_frontend/es2panda/ir/module/exportAllDeclaration.h" 95 | #include "../ets_frontend/es2panda/ir/module/exportNamedDeclaration.h" 96 | #include "../ets_frontend/es2panda/ir/module/exportSpecifier.h" 97 | 98 | #include "../ets_frontend/es2panda/ir/astNode.h" 99 | 100 | #include "../ets_frontend/es2panda/parser/parserImpl.h" 101 | 102 | #include "../ets_frontend/es2panda/lexer/token/sourceLocation.h" 103 | #include "../ets_frontend/es2panda/lexer/token/tokenType.h" 104 | 105 | #include "../ets_frontend/es2panda/util/ustring.h" 106 | 107 | 108 | 109 | template 110 | static T *AllocNode(panda::es2panda::parser::Program *parser_program_, Args &&... args) 111 | { 112 | auto ret = parser_program_->Allocator()->New(std::forward(args)...); 113 | if (ret == nullptr) { 114 | std::cout << "Unsuccessful allocation during parsing" << std::endl;; 115 | } 116 | return ret; 117 | } 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /tests/8.class.ts: -------------------------------------------------------------------------------- 1 | // class Animal { 2 | // name: string; 3 | 4 | // constructor(name: string) { 5 | // this.name = name; 6 | // } 7 | 8 | // move(): void { 9 | // console.log(`${this.name} is moving`); 10 | // } 11 | // } 12 | 13 | // interface Flyable { 14 | // fly(): void; 15 | // } 16 | 17 | // interface Swimmable { 18 | // swim(): void; 19 | // } 20 | 21 | // class Bird extends Animal implements Flyable { 22 | // constructor(name: string) { 23 | // super(name); 24 | // } 25 | 26 | // fly(): void { 27 | // console.log(`${this.name} is flying`); 28 | // } 29 | 30 | // move(): void { 31 | // console.log(`${this.name} is hopping and flying`); 32 | // } 33 | // } 34 | 35 | // class Fish extends Animal implements Swimmable { 36 | // constructor(name: string) { 37 | // super(name); 38 | // } 39 | 40 | // swim(): void { 41 | // console.log(`${this.name} is swimming`); 42 | // } 43 | 44 | // move(): void { 45 | // console.log(`${this.name} is swimming gracefully`); 46 | // } 47 | // } 48 | 49 | // class Duck extends Animal implements Flyable, Swimmable { 50 | // constructor(name: string) { 51 | // super(name); 52 | // } 53 | 54 | // fly(): void { 55 | // console.log(`${this.name} is flying`); 56 | // } 57 | 58 | // swim(): void { 59 | // console.log(`${this.name} is swimming`); 60 | // } 61 | 62 | // move(): void { 63 | // console.log(`${this.name} is waddling, swimming, and flying`); 64 | // } 65 | // } 66 | 67 | // const sparrow = new Bird("Sparrow"); 68 | // sparrow.move(); 69 | // sparrow.fly(); 70 | 71 | // const goldfish = new Fish("Goldfish"); 72 | // goldfish.move(); 73 | // goldfish.swim(); 74 | 75 | // const donald = new Duck("Donald"); 76 | // donald.move(); 77 | // donald.fly(); 78 | // donald.swim(); 79 | 80 | 81 | // # 28. LDPRIVATEPROPERTY_IMM8_IMM16_IMM16 82 | // class XXX { 83 | // #yyy: number = 8; 84 | // #zzz: number = 9; 85 | // #add1() { 86 | // this.#yyy += 1; 87 | // } 88 | 89 | // #add2() { 90 | // this.#zzz += 2; 91 | // } 92 | 93 | // sub() { 94 | // this.#yyy -= 3; 95 | // this.#add1(); 96 | // this.#add2(); 97 | // } 98 | // } 99 | // var xxx = new XXX(); 100 | 101 | // class YYY { 102 | // #yyy1: number = 8; 103 | // #zzz1: number = 9; 104 | // #adda() { 105 | // this.#yyy1 += 1; 106 | // } 107 | 108 | // #addb() { 109 | // this.#zzz1 += 2; 110 | // } 111 | 112 | // sub() { 113 | // this.#yyy1 -= 3; 114 | // this.#adda(); 115 | // this.#addb(); 116 | // } 117 | // } 118 | 119 | // var yyy = new YYY(); 120 | // function hello() { 121 | // function hi() { 122 | // var x1 = 21; 123 | // let x2 = function () { 124 | // return x1; 125 | // }; 126 | // } 127 | // } 128 | 129 | 130 | // 29. ldsuperbyvalue ldsuperbyname stsuperbyname stsuperbyvalue supercallforwardallargs 131 | // class Animal { 132 | // constructor(name: string) { 133 | // this.name = name; 134 | // } 135 | 136 | // makeSound() { 137 | // console.log(this.name); 138 | // } 139 | // } 140 | 141 | // class Dog extends Animal { 142 | // makeSound() { 143 | // super.makeSound(); 144 | // var x = super["name"]; 145 | // console.log(x); 146 | // } 147 | 148 | // makeDance(){ 149 | // super.name = "dance"; 150 | // super["name"] = "dog"; 151 | // } 152 | // } 153 | 154 | // const myDog = new Dog("Buddy", "Golden Retriever"); 155 | // myDog.makeSound(); 156 | 157 | // 30. ldthisbyname ldthisbyvalue stthisbyname stthisbyvalue 158 | // class Animal { 159 | // constructor(name: string) { 160 | // this.name = name; 161 | // } 162 | 163 | // makeDance(){ 164 | // console.log(this["hello"]); 165 | // } 166 | // } 167 | 168 | // 31. sendable 169 | // class SendableB { 170 | // constructor() { 171 | // "use sendable"; 172 | // } 173 | 174 | // hello(){ 175 | // this.name = "hello"; 176 | // console.log("11"); 177 | // } 178 | // } 179 | 180 | // function test2() { 181 | // var a = new SendableB(); 182 | // var b = 1; 183 | // function hi() { 184 | // var m = a; 185 | // console.log(m); 186 | // var n = b; 187 | // console.log(n); 188 | // } 189 | // } 190 | 191 | // 32. ldsendableclass DEFINEPROPERTYBYNAME 192 | // class B { 193 | // constructor() { 194 | // "use sendable"; 195 | // } 196 | // static b: number = 1; 197 | // b: number = B.b; 198 | // //c: number = B["b"]; 199 | // } 200 | 201 | // 37. COPYRESTARGS SUPERCALLSPREAD 202 | // class A {} 203 | // class B extends A { 204 | // constructor(...args) { 205 | // super(1, ...args) 206 | // } 207 | // } 208 | 209 | 210 | // 42. definegettersetterbyvalue 211 | // class Example { 212 | // constructor(value) { 213 | // this._value = value; 214 | // } 215 | 216 | // // Getter 217 | // get value() { 218 | // console.log('Getting value'); 219 | // return this._value; 220 | // } 221 | 222 | // // Setter 223 | // set value(newValue) { 224 | // console.log('Setting value'); 225 | // this._value = newValue; 226 | // } 227 | // } 228 | 229 | // const example = new Example(10); 230 | 231 | 232 | // 41. stownbyvaluewithnameset topropertykey 233 | // class A5 { 234 | // [a5]() {} 235 | // } 236 | 237 | // 42. definegettersetterbyvalue 238 | // class Example { 239 | // constructor(value) { 240 | // this._value = value; 241 | // } 242 | 243 | // // Getter 244 | // get value() { 245 | // console.log('Getting value'); 246 | // return this._value; 247 | // } 248 | 249 | // // Setter 250 | // set value(newValue) { 251 | // console.log('Setting value'); 252 | // this._value = newValue; 253 | // } 254 | // } 255 | 256 | // const example = new Example(10); 257 | 258 | // 37. COPYRESTARGS SUPERCALLSPREAD 259 | // class A {} 260 | // class B extends A { 261 | // constructor(...args) { 262 | // super(1, ...args) 263 | // } 264 | // } 265 | 266 | 267 | // 41. getunmappedargs stownbyvaluewithnameset topropertykey 268 | // class A5 { 269 | // [a5]() {} 270 | // } -------------------------------------------------------------------------------- /classconstruction.cpp: -------------------------------------------------------------------------------- 1 | #include "classconstruction.h" 2 | 3 | bool ConstructClasses(std::map> &class2memberfuns, panda::es2panda::parser::Program *parser_program, BytecodeOptIrInterface *ir_interface, 4 | std::map &class2father, std::map &method2scriptfunast, 5 | std::map &ctor2classdeclast, std::map& raw2newname 6 | ){ 7 | 8 | for(const auto & pair : class2memberfuns){ 9 | auto constructor_offset = pair.first; 10 | 11 | std::cout << constructor_offset << std::endl; 12 | 13 | auto member_funcs = pair.second; 14 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 15 | auto constructor_offset_name = RemoveArgumentsOfFunc(ir_interface->GetMethodIdByOffset(constructor_offset)); 16 | std::string newname_constructor_offset_name; 17 | 18 | if(raw2newname.find(constructor_offset_name) != raw2newname.end()){ 19 | newname_constructor_offset_name = raw2newname[constructor_offset_name]; 20 | }else{ 21 | HandleError("#ConstructClasses: find constructor_offset_name newname error"); 22 | } 23 | 24 | panda::es2panda::util::StringView name_view1 = panda::es2panda::util::StringView(*(new std::string(RemoveArgumentsOfFunc(newname_constructor_offset_name)))); 25 | 26 | auto identNode = AllocNode(parser_program, name_view1); 27 | 28 | 29 | ArenaVector implements(parser_program->Allocator()->Adapter()); 30 | ArenaVector indexSignatures(parser_program->Allocator()->Adapter()); 31 | ArenaVector properties(parser_program->Allocator()->Adapter()); 32 | 33 | ////////////////////////////////////////////////////////////////////////////////////////////// 34 | ArenaVector decorators(parser_program->Allocator()->Adapter()); 35 | ArenaVector annotations(parser_program->Allocator()->Adapter()); 36 | ArenaVector paramDecorators(parser_program->Allocator()->Adapter()); 37 | 38 | panda::es2panda::util::StringView name_view2 = panda::es2panda::util::StringView("constructor"); 39 | auto keyNode = AllocNode(parser_program, name_view2); 40 | 41 | auto func = method2scriptfunast[constructor_offset]; 42 | method2scriptfunast.erase(constructor_offset); 43 | 44 | if(func == nullptr){ 45 | HandleError("#DecompilePandaFile: find constructor function fail!"); 46 | } 47 | 48 | auto funcExpr = AllocNode(parser_program, func); 49 | 50 | 51 | auto ctor = AllocNode(parser_program, es2panda::ir::MethodDefinitionKind::CONSTRUCTOR, keyNode, funcExpr, 52 | es2panda::ir::ModifierFlags::PUBLIC, parser_program->Allocator(), 53 | std::move(decorators), std::move(annotations), 54 | std::move(paramDecorators), false); 55 | 56 | /////////////////////////////////////////////////////////////////////////////////////////////// 57 | 58 | auto father = class2father[constructor_offset]; 59 | auto classDefinition = AllocNode(parser_program, nullptr, identNode, nullptr, nullptr, 60 | std::move(implements), ctor, nullptr, 61 | nullptr, father, std::move(properties), 62 | std::move(indexSignatures), false, false); 63 | 64 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 65 | 66 | for (const auto& member_func_offset : member_funcs) { 67 | if(constructor_offset == member_func_offset){ 68 | continue; 69 | } 70 | 71 | auto func = method2scriptfunast[member_func_offset]; 72 | method2scriptfunast.erase(member_func_offset); 73 | 74 | if(func == nullptr){ 75 | std::cout << "member function offset: " << member_func_offset << std::endl; 76 | HandleError("#ConstructClasses: find member function fail!"); 77 | } 78 | 79 | auto funcExpr = AllocNode(parser_program, func); 80 | 81 | 82 | auto raw_member_name = RemoveArgumentsOfFunc(ir_interface->GetMethodIdByOffset(member_func_offset)); 83 | std::string new_member_name; 84 | if(raw2newname.find(raw_member_name) != raw2newname.end()){ 85 | new_member_name = raw2newname[raw_member_name]; 86 | }else{ 87 | HandleError("#ConstructClasses: find new_member_name newname error"); 88 | } 89 | 90 | panda::es2panda::util::StringView name_view3 = panda::es2panda::util::StringView(*(new std::string(new_member_name))); 91 | auto keyNode = AllocNode(parser_program, name_view3); 92 | 93 | ArenaVector decorators(parser_program->Allocator()->Adapter()); 94 | ArenaVector annotations(parser_program->Allocator()->Adapter()); 95 | ArenaVector paramDecorators(parser_program->Allocator()->Adapter()); 96 | 97 | 98 | 99 | auto method = AllocNode(parser_program, es2panda::ir::MethodDefinitionKind::METHOD, keyNode, funcExpr, 100 | es2panda::ir::ModifierFlags::PUBLIC, parser_program->Allocator(), 101 | std::move(decorators), std::move(annotations), 102 | std::move(paramDecorators), false); 103 | classDefinition->AddToBody(method); 104 | 105 | } 106 | 107 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 108 | ArenaVector decorators1(parser_program->Allocator()->Adapter()); 109 | ArenaVector annotations1(parser_program->Allocator()->Adapter()); 110 | 111 | 112 | auto classDecl = AllocNode(parser_program, classDefinition, 113 | std::move(decorators1), std::move(annotations1), false); 114 | 115 | ctor2classdeclast[constructor_offset] = classDecl; 116 | } 117 | return true; 118 | } 119 | -------------------------------------------------------------------------------- /arkts.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_ARKTS 2 | #define DECOMPILER_ARKTS 3 | 4 | #include "base.h" 5 | 6 | namespace panda::es2panda::ir { 7 | 8 | class ArkTSGen { 9 | public: 10 | class Nullable { 11 | public: 12 | explicit Nullable(const ir::AstNode *node) : node_(node) {} 13 | 14 | const ir::AstNode *Node() const 15 | { 16 | return node_; 17 | } 18 | 19 | private: 20 | const ir::AstNode *node_; 21 | }; 22 | 23 | class Optional { 24 | public: 25 | using Val = std::variant; 26 | explicit Optional(const ir::AstNode *node) : value_(node) {} 27 | explicit Optional(const char *string) : value_(const_cast(string)) {} 28 | explicit Optional(bool boolean) : value_(boolean) {} 29 | 30 | const Val &Value() const 31 | { 32 | return value_; 33 | } 34 | 35 | private: 36 | Val value_; 37 | }; 38 | 39 | class Property { 40 | public: 41 | class Ignore { 42 | public: 43 | Ignore() = default; 44 | }; 45 | 46 | enum class Constant { 47 | PROP_NULL, 48 | EMPTY_ARRAY, 49 | PROP_UNDEFINED 50 | }; 51 | 52 | using Val = 53 | std::variant, util::StringView, bool, 54 | double, const ir::AstNode *, std::vector, Constant, Nullable, Ignore>; 55 | 56 | Property(const char *string) : value_(string) {} 57 | Property(util::StringView str) : value_(str) {} 58 | Property(bool boolean) : value_(boolean) {} 59 | Property(double number) : value_(number) {} 60 | Property(lexer::TokenType token) : value_(token) {} 61 | Property(std::initializer_list props) : value_(props) {} 62 | Property(const ir::AstNode *node) : value_(const_cast(node)) {} 63 | 64 | Property(Constant constant) : value_(constant) {} 65 | Property(Nullable nullable) 66 | { 67 | if (nullable.Node()) { 68 | value_ = nullable.Node(); 69 | } else { 70 | value_ = Property::Constant::PROP_NULL; 71 | } 72 | } 73 | 74 | Property(Optional optional) 75 | { 76 | const auto &value = optional.Value(); 77 | if (std::holds_alternative(value) && std::get(value)) { 78 | value_ = std::get(value); 79 | return; 80 | } 81 | 82 | if (std::holds_alternative(value) && std::get(value)) { 83 | value_ = std::get(value); 84 | return; 85 | } 86 | 87 | if (std::holds_alternative(value) && std::get(value)) { 88 | value_ = std::get(value); 89 | return; 90 | } 91 | 92 | value_ = Ignore(); 93 | } 94 | 95 | template 96 | Property(const ArenaVector &array) 97 | { 98 | if (array.empty()) { 99 | value_ = Constant::EMPTY_ARRAY; 100 | return; 101 | } 102 | 103 | std::vector nodes; 104 | nodes.reserve(array.size()); 105 | 106 | for (auto &it : array) { 107 | nodes.push_back(it); 108 | } 109 | 110 | value_ = std::move(nodes); 111 | } 112 | 113 | const char *Key() const 114 | { 115 | return key_; 116 | } 117 | 118 | const Val &Value() const 119 | { 120 | return value_; 121 | } 122 | 123 | private: 124 | const char *key_; 125 | Val value_ {false}; 126 | }; 127 | 128 | explicit ArkTSGen(const BlockStatement *program, util::StringView sourceCode); 129 | explicit ArkTSGen(const ir::AstNode *node); 130 | 131 | void EmitStatement(const ir::AstNode *node); 132 | 133 | void Add(std::initializer_list props); 134 | void Add(const ArkTSGen::Property &prop); 135 | 136 | static const char *ModifierToString(ModifierFlags flags); 137 | static const char *TypeOperatorToString(TSOperatorType operatorType); 138 | 139 | std::string Str() const 140 | { 141 | return ss_.str(); 142 | } 143 | 144 | private: 145 | using WrapperCb = std::function; 146 | 147 | template 148 | void AddList(T props) 149 | { 150 | for (auto it = props.begin(); it != props.end();) { 151 | Serialize(*it); 152 | 153 | do { 154 | if (++it == props.end()) { 155 | return; 156 | } 157 | } while (std::holds_alternative((*it).Value())); 158 | 159 | ss_ << ','; 160 | } 161 | } 162 | 163 | void Indent(); 164 | 165 | void EmitBlockStatement(const ir::AstNode *node); 166 | 167 | void WriteTrailingSemicolon(); //; 168 | void WriteSpace(); 169 | void WriteLeftBrace(); // { 170 | void WriteRightBrace(); // } 171 | void WriteLeftBracket(); // [ 172 | void WriteRightBracket(); // ] 173 | 174 | void WriteLeftParentheses(); // ( 175 | void WriteRightParentheses(); // ) 176 | 177 | 178 | void WriteColon();// : 179 | void WriteEqual();// = 180 | void WriteComma();// , 181 | void WriteDot(); // . 182 | void WriteSpreadDot(); // ... 183 | void WriteKeyWords(std::string keyword); 184 | void WriteNewLine(); 185 | void WriteIndent(); 186 | 187 | void EmitExpression(const ir::AstNode *node); 188 | void EmitExpressionStatement(const ir::AstNode *node); 189 | void EmitVariableDeclarationStatement(const ir::AstNode *node); 190 | void EmitVariableDeclaratorStatement(const ir::AstNode *node); 191 | void EmitReturnStatement(const ir::AstNode *node); 192 | void EmitBreakStatement(const ir::AstNode *node); 193 | 194 | void EmitDebuggerStatement(const ir::AstNode *node); 195 | void EmitIfStatement(const ir::AstNode *node); 196 | void EmitTryStatement(const ir::AstNode *node); 197 | void EmitThrowStatement(const ir::AstNode *node); 198 | void EmitWhileStatement(const ir::AstNode *node); 199 | void EmitDoWhileStatement(const ir::AstNode *node); 200 | 201 | void EmitImportSpecifier(const ir::AstNode *node); 202 | void EmitImportDeclaration(const ir::AstNode *node); 203 | 204 | void EmitExportAllDeclaration(const ir::AstNode *node); 205 | void EmitExportSpecifier(const ir::AstNode *node); 206 | void EmitExportNamedDeclaration(const ir::AstNode *node); 207 | 208 | void EmitClassDeclaration(const ir::AstNode *node); 209 | void EmitMethodDefinition(const ir::AstNode *node); 210 | 211 | void EmitFunctionDeclaration(const ir::AstNode *node); 212 | 213 | void Serialize(const ArkTSGen::Property &prop); 214 | void SerializePropKey(const char *str); 215 | void SerializeString(const char *str); 216 | void SerializeString(const util::StringView &str); 217 | void SerializeNumber(size_t number); 218 | void SerializeNumber(double number); 219 | void SerializeBoolean(bool boolean); 220 | void SerializeObject(const ir::AstNode *object); 221 | void SerializeToken(lexer::TokenType token); 222 | void SerializePropList(std::initializer_list props); 223 | void SerializeConstant(Property::Constant constant); 224 | void Wrap(const WrapperCb &cb, char delimStart = '{', char delimEnd = '}'); 225 | 226 | void SerializeArray(std::vector array); 227 | 228 | lexer::LineIndex index_; 229 | std::stringstream ss_; 230 | int32_t indent_; 231 | int32_t singleindent_ = 2; 232 | bool dumpNodeOnly_ = true; 233 | 234 | 235 | 236 | 237 | 238 | }; 239 | } // namespace panda::es2panda::ir 240 | 241 | #endif // ASTDUMP_H 242 | -------------------------------------------------------------------------------- /autotests/scantstests.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import shutil 4 | import subprocess 5 | import json 6 | import sys 7 | import signal 8 | import copy 9 | import ipdb 10 | from pathlib import Path 11 | 12 | env_vars = copy.deepcopy(os.environ) 13 | env_vars['LD_LIBRARY_PATH'] = '../out/arkcompiler/runtime_core:../out/thirdparty/zlib' 14 | 15 | def execute_cmd(cmd): 16 | status_detail = "" 17 | return_code = None 18 | 19 | try: 20 | result = subprocess.run( 21 | cmd, 22 | check=False, 23 | stdout=subprocess.PIPE, 24 | stderr=subprocess.PIPE, 25 | universal_newlines=True, 26 | start_new_session=True, 27 | timeout=10, 28 | env=env_vars, 29 | #shell=True 30 | ) 31 | 32 | return_code = result.returncode 33 | 34 | if result.returncode == 0: 35 | print(f"✅ Success (Exit Code 0)") 36 | status_detail = "Success" 37 | elif result.returncode == 1: 38 | print(f"❌ Warning: failure (std::exit(EXIT_FAILURE), Exit Code 1)!") 39 | status_detail = "Error (EXIT_FAILURE)" 40 | elif result.returncode < 0: 41 | # Negative return codes indicate termination by signal on Linux 42 | signal_value = abs(result.returncode) 43 | signal_name = signal.Signals(signal_value).name if 1 <= signal_value <= 64 else f"Signal {signal_value}" 44 | 45 | if signal_value == signal.SIGSEGV.value: 46 | print(f"❌ Severe Error: Segmentation Fault ({signal_name})!") 47 | status_detail = "Segmentation Fault" 48 | else: 49 | print(f"❌ Warning: terminated by signal ({signal_name})!") 50 | status_detail = f"Error (Signal: {signal_name})" 51 | else: 52 | # Other non-zero return codes 53 | print(f"❌ Warning: exited abnormally (Exit Code {result.returncode})!") 54 | status_detail = f"Error (Exit Code {result.returncode})" 55 | 56 | except subprocess.TimeoutExpired as e: 57 | print(f"❌ Timeout Error: Process timed out.") 58 | status_detail = "Timeout Expired" 59 | return_code = -1 60 | except FileNotFoundError: 61 | print(f"Error: Executable not found. Please check the path configuration.") 62 | status_detail = "Error (Executable Not Found)" 63 | return_code = -2 64 | except Exception as e: 65 | print(f"An error occurred during execution : {e}") 66 | status_detail = f"Error (Execution Exception: {str(e)})" 67 | return_code = -3 68 | finally: 69 | os.system("pkill -f -9 xabc") 70 | 71 | res = { 72 | "status": status_detail, 73 | "return_code": return_code 74 | } 75 | return res 76 | 77 | def load_results(results_path): 78 | if os.path.exists(results_path): 79 | try: 80 | with open(results_path, 'r', encoding='utf-8') as f: 81 | results_list = json.load(f) 82 | analyzed_paths = {item.get("file") for item in results_list if item.get("file")} 83 | return results_list, analyzed_paths 84 | except json.JSONDecodeError: 85 | print(f"Warning: Could not parse {results_path}, creating new results.") 86 | return [], set() 87 | 88 | def analysis_onefile(analysis_file): 89 | #cpcmd = f"cp {analysis_file} demo.ts" 90 | #compilecmd = "../../out/x64.release/arkcompiler/ets_frontend/es2abc --module --dump-assembly demo.ts --output demo.abc" 91 | #decompilecmd = "LD_LIBRARY_PATH=../out/arkcompiler/runtime_core:../out/thirdparty/zlib ../out/arkcompiler/common/xabc" 92 | 93 | cpcmd = ["cp", analysis_file, "demo.ts"] 94 | compilecmd = ["../../out/x64.release/arkcompiler/ets_frontend/es2abc", "--module", "--dump-assembly", "demo.ts", "--output", "demo.abc"] 95 | decompilecmd = ["../out/arkcompiler/common/xabc"] 96 | 97 | res = {} 98 | 99 | res["file"] = analysis_file 100 | 101 | cp_res = execute_cmd(cpcmd) 102 | if cp_res["return_code"] != 0: 103 | res["status"] = 1 104 | return res 105 | 106 | compile_res = execute_cmd(compilecmd) 107 | if compile_res["return_code"] != 0: 108 | res["status"] = 2 109 | return res 110 | 111 | decompile_res = execute_cmd(decompilecmd) 112 | if decompile_res["return_code"] != 0: 113 | res["status"] = 3 114 | return res 115 | 116 | res["status"] = 0 117 | 118 | return res 119 | 120 | def save_results(results_list, output_dir): 121 | results_path = Path(output_dir) / "res.json" 122 | with open(results_path, 'w', encoding='utf-8') as f: 123 | json.dump(results_list, f, ensure_ascii=False, indent=4) 124 | 125 | grouped_results = {} 126 | for result_entry in results_list: 127 | status_code = result_entry.get("status") 128 | if status_code is not None: 129 | if status_code not in grouped_results: 130 | grouped_results[status_code] = [] 131 | grouped_results[status_code].append(result_entry) 132 | else: 133 | # Handle entries that somehow lack a status code 134 | if "unknown_status" not in grouped_results: 135 | grouped_results["unknown_status"] = [] 136 | grouped_results["unknown_status"].append(result_entry) 137 | 138 | print(f"Distributing results into files based on status code:") 139 | for status_code, records in grouped_results.items(): 140 | # Ensure the filename is valid (e.g., status 0 -> 0.json, status -11 -> negative_11.json) 141 | filename = f"{status_code}.json" 142 | if isinstance(status_code, int) and status_code < 0: 143 | filename = f"negative_{abs(status_code)}.json" 144 | 145 | filepath = Path(output_dir) / filename 146 | 147 | with open(filepath, 'w', encoding='utf-8') as f: 148 | json.dump(records, f, ensure_ascii=False, indent=4) 149 | 150 | print(f" - Status {status_code}: Saved {len(records)} records to {filepath}") 151 | 152 | def analysis_files(root_dir, output_dir): 153 | ts_files = list(root_dir.rglob('*.ts')) 154 | total_files = len(ts_files) 155 | results_path = Path(output_dir) / "res.json" 156 | 157 | results_list, analyzed_paths = load_results(str(results_path.resolve())) 158 | print(f"Loaded {len(analyzed_paths)} historical analysis records.") 159 | 160 | for i, ts_file in enumerate(ts_files): 161 | if ts_file not in analyzed_paths: 162 | print(f"\n[{i+1}/{total_files}] ", end="") 163 | print(f"analysis: {ts_file}") 164 | res = analysis_onefile(str(ts_file.resolve())) 165 | print(res) 166 | results_list.append(res) 167 | else: 168 | analyzed_paths.add(ts_file) 169 | 170 | save_results(results_list, output_dir) 171 | 172 | if __name__ == "__main__": 173 | parser = argparse.ArgumentParser(description="Recursively analyze TS files using the abc tool.") 174 | parser.add_argument("-i", "--input_dir", type=str, default="../autotests/third_party_typescript/tests", 175 | help=f"Root directory to scan for TS files (default: '../autotests/third_party_typescript/tests')") 176 | 177 | parser.add_argument("-o", "--output_dir", type=str, default="status_outputs", 178 | help=f"Directory to save status-specific JSON files (default: 'status_outputs')") 179 | 180 | parser.add_argument("-d", "--record_file", type=str, default="res.json", 181 | help=f"JSON file path for analyzed file records (default: res.json)") 182 | args = parser.parse_args() 183 | root_dir = Path(args.input_dir) 184 | if not root_dir.is_dir(): 185 | print(f"Error: '{args.input_dir}' is not a valid directory.") 186 | sys.exit(1) 187 | 188 | if not os.path.exists(args.output_dir): 189 | os.makedirs(args.output_dir) 190 | print(f"\nCreated output directory: {args.output_dir}") 191 | 192 | analysis_files(root_dir, args.output_dir) 193 | 194 | #test_file = "../autotests/third_party_typescript/tests/cases/conformance/emitter/es2015/asyncGenerators/emitter.asyncGenerators.classMethods.es2015.ts" 195 | #analysis_onefile(test_file) 196 | 197 | 198 | -------------------------------------------------------------------------------- /intrinsicid2token.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPILER_INTRINSIC2TOKEN 2 | #define DECOMPILER_INTRINSIC2TOKEN 3 | 4 | #include "intrinsicid2name.h" 5 | 6 | panda::es2panda::lexer::TokenType BinIntrinsicIdToToken(panda::compiler::RuntimeInterface::IntrinsicId id){ 7 | 8 | switch (id) { 9 | case panda::compiler::RuntimeInterface::IntrinsicId::AND2_IMM8_V8: 10 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_BITWISE_AND; 11 | case panda::compiler::RuntimeInterface::IntrinsicId::OR2_IMM8_V8: 12 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_BITWISE_OR; 13 | case panda::compiler::RuntimeInterface::IntrinsicId::MUL2_IMM8_V8: 14 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_MULTIPLY; 15 | case panda::compiler::RuntimeInterface::IntrinsicId::DIV2_IMM8_V8: 16 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_DIVIDE; 17 | case panda::compiler::RuntimeInterface::IntrinsicId::SUB2_IMM8_V8: 18 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_MINUS; 19 | case panda::compiler::RuntimeInterface::IntrinsicId::NOT_IMM8: 20 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_TILDE; 21 | case panda::compiler::RuntimeInterface::IntrinsicId::SHL2_IMM8_V8: 22 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LEFT_SHIFT; 23 | case panda::compiler::RuntimeInterface::IntrinsicId::ASHR2_IMM8_V8: 24 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT; 25 | case panda::compiler::RuntimeInterface::IntrinsicId::LESSEQ_IMM8_V8: 26 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL; 27 | case panda::compiler::RuntimeInterface::IntrinsicId::GREATEREQ_IMM8_V8: 28 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL; 29 | case panda::compiler::RuntimeInterface::IntrinsicId::MOD2_IMM8_V8: 30 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_MOD; 31 | case panda::compiler::RuntimeInterface::IntrinsicId::XOR2_IMM8_V8: 32 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_BITWISE_XOR; 33 | 34 | case panda::compiler::RuntimeInterface::IntrinsicId::EXP_IMM8_V8: 35 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_EXPONENTIATION; 36 | 37 | case panda::compiler::RuntimeInterface::IntrinsicId::SHR2_IMM8_V8: 38 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT; 39 | 40 | case panda::compiler::RuntimeInterface::IntrinsicId::ADD2_IMM8_V8: 41 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_PLUS; 42 | 43 | ///////////////////////// 44 | 45 | case panda::compiler::RuntimeInterface::IntrinsicId::LESS_IMM8_V8: 46 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN; 47 | 48 | case panda::compiler::RuntimeInterface::IntrinsicId::GREATER_IMM8_V8: 49 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN; 50 | 51 | case panda::compiler::RuntimeInterface::IntrinsicId::EQ_IMM8_V8: 52 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_EQUAL; 53 | 54 | case panda::compiler::RuntimeInterface::IntrinsicId::NOTEQ_IMM8_V8: 55 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_EQUAL; 56 | 57 | case panda::compiler::RuntimeInterface::IntrinsicId::STRICTEQ_IMM8_V8: 58 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_STRICT_EQUAL; 59 | 60 | case panda::compiler::RuntimeInterface::IntrinsicId::STRICTNOTEQ_IMM8_V8: 61 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL; 62 | 63 | 64 | case panda::compiler::RuntimeInterface::IntrinsicId::INSTANCEOF_IMM8_V8: 65 | return panda::es2panda::lexer::TokenType::KEYW_INSTANCEOF; 66 | case panda::compiler::RuntimeInterface::IntrinsicId::ISIN_IMM8_V8: 67 | return panda::es2panda::lexer::TokenType::KEYW_IN; 68 | 69 | default: 70 | std::cout << "S6" << std::endl; 71 | UNREACHABLE(); 72 | } 73 | } 74 | 75 | panda::es2panda::lexer::TokenType BinInverseToken2Token(panda::es2panda::lexer::TokenType id){ 76 | switch (id) { 77 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: 78 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN; 79 | 80 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: 81 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN; 82 | 83 | 84 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN: 85 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL; 86 | 87 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN: 88 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL; 89 | 90 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_EQUAL: 91 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_EQUAL; 92 | 93 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_EQUAL: 94 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_EQUAL; 95 | 96 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: 97 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL; 98 | 99 | case panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: 100 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_STRICT_EQUAL; 101 | 102 | default: 103 | return id; 104 | } 105 | } 106 | 107 | 108 | panda::es2panda::lexer::TokenType BinInverseIntrinsicIdToToken(panda::compiler::RuntimeInterface::IntrinsicId id){ 109 | 110 | switch (id) { 111 | case panda::compiler::RuntimeInterface::IntrinsicId::LESSEQ_IMM8_V8: 112 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN; 113 | 114 | case panda::compiler::RuntimeInterface::IntrinsicId::GREATEREQ_IMM8_V8: 115 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN; 116 | 117 | 118 | case panda::compiler::RuntimeInterface::IntrinsicId::LESS_IMM8_V8: 119 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL; 120 | 121 | case panda::compiler::RuntimeInterface::IntrinsicId::GREATER_IMM8_V8: 122 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL; 123 | 124 | case panda::compiler::RuntimeInterface::IntrinsicId::EQ_IMM8_V8: 125 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_EQUAL; 126 | 127 | case panda::compiler::RuntimeInterface::IntrinsicId::NOTEQ_IMM8_V8: 128 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_EQUAL; 129 | 130 | case panda::compiler::RuntimeInterface::IntrinsicId::STRICTEQ_IMM8_V8: 131 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL; 132 | 133 | case panda::compiler::RuntimeInterface::IntrinsicId::STRICTNOTEQ_IMM8_V8: 134 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_STRICT_EQUAL; 135 | 136 | default: 137 | std::cout << "S7" << std::endl; 138 | UNREACHABLE(); 139 | } 140 | } 141 | 142 | 143 | panda::es2panda::lexer::TokenType UnaryPrefixIntrinsicIdToToken(panda::compiler::RuntimeInterface::IntrinsicId id){ 144 | 145 | switch (id) { 146 | case panda::compiler::RuntimeInterface::IntrinsicId::NEG_IMM8: 147 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_MINUS; 148 | case panda::compiler::RuntimeInterface::IntrinsicId::NOT_IMM8: 149 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_TILDE; 150 | case panda::compiler::RuntimeInterface::IntrinsicId::TYPEOF_IMM8: 151 | return panda::es2panda::lexer::TokenType::KEYW_TYPEOF; 152 | case panda::compiler::RuntimeInterface::IntrinsicId::DELOBJPROP_V8: 153 | return panda::es2panda::lexer::TokenType::KEYW_DELETE; 154 | default: 155 | std::cout << "S8: " << GetIntrinsicOpcodeName(id) << std::endl; 156 | UNREACHABLE(); 157 | } 158 | } 159 | 160 | 161 | panda::es2panda::lexer::TokenType IncDecIntrinsicIdToToken(panda::compiler::RuntimeInterface::IntrinsicId id){ 162 | switch (id) { 163 | case panda::compiler::RuntimeInterface::IntrinsicId::DEC_IMM8: 164 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_MINUS; 165 | 166 | case panda::compiler::RuntimeInterface::IntrinsicId::INC_IMM8: 167 | return panda::es2panda::lexer::TokenType::PUNCTUATOR_PLUS; 168 | default: 169 | std::cout << "S9" << std::endl; 170 | UNREACHABLE(); 171 | 172 | } 173 | } 174 | #endif -------------------------------------------------------------------------------- /lexicalenv.cpp: -------------------------------------------------------------------------------- 1 | #include "lexicalenv.h" 2 | #include 3 | #include 4 | 5 | 6 | 7 | LexicalEnv::LexicalEnv(size_t capacity) 8 | : expressions_(capacity, nullptr), capacity_(capacity), full_size_(0) { 9 | } 10 | 11 | void LexicalEnv::AddIndexes(size_t index){ 12 | indexes_.insert(index); 13 | } 14 | 15 | 16 | bool LexicalEnv::IsFull() const { 17 | for (size_t i = 0; i < capacity_; ++i) { 18 | if(expressions_[i] == nullptr){ 19 | //HandleError("#LexicalEnv::IsFull : " + std::to_string(i)); 20 | return false; 21 | } 22 | } 23 | return true; 24 | } 25 | 26 | LexicalEnv::LexicalEnv(const LexicalEnv& other) 27 | : expressions_(other.capacity_), capacity_(other.capacity_), full_size_(other.full_size_){ 28 | 29 | for (size_t i = 0; i < capacity_; ++i) { 30 | if(other.expressions_[i] == nullptr){ 31 | }else{ 32 | expressions_[i] = new std::string(*(other.expressions_[i])); 33 | } 34 | } 35 | 36 | indexes_.insert(other.indexes_.begin(), other.indexes_.end()); 37 | } 38 | 39 | std::string*& LexicalEnv::operator[](size_t index) { 40 | CheckIndex(index); 41 | return expressions_[index]; 42 | } 43 | 44 | const std::string* LexicalEnv::operator[](size_t index) const { 45 | CheckIndex(index); 46 | return expressions_[index]; 47 | } 48 | 49 | std::string* LexicalEnv::Get(size_t index) const { 50 | CheckIndex(index); 51 | return expressions_[index]; 52 | } 53 | 54 | void LexicalEnv::Set(size_t index, std::string* expr) { 55 | CheckIndex(index); 56 | expressions_[index] = expr; 57 | AddIndexes(index); /// support callruntime.createprivateproperty 58 | } 59 | 60 | size_t LexicalEnv::Size() const { 61 | for (size_t i = 0; i < capacity_; ++i) { 62 | if(expressions_[i] != nullptr){ 63 | full_size_ = i; 64 | } 65 | } 66 | return full_size_; 67 | } 68 | 69 | bool LexicalEnv::IsValidIndex(size_t index) const { 70 | return index < capacity_; 71 | } 72 | 73 | void LexicalEnv::CheckIndex(size_t index) const { 74 | if (index >= capacity_) { 75 | throw std::out_of_range("LexicalEnv index out of range"); 76 | } 77 | } 78 | 79 | LexicalEnvStack::LexicalEnvStack() { 80 | } 81 | 82 | LexicalEnvStack::LexicalEnvStack(const LexicalEnvStack& other) 83 | : stack_(other.stack_) { 84 | } 85 | 86 | bool LexicalEnvStack::IsFull() const { 87 | for(auto const &lexicalenv : stack_){ 88 | if(!lexicalenv.IsFull()){ 89 | return false; 90 | } 91 | } 92 | return true; 93 | } 94 | 95 | LexicalEnvStack::~LexicalEnvStack() { 96 | } 97 | 98 | LexicalEnv* LexicalEnvStack::Push(size_t capacity) { 99 | stack_.emplace_back(capacity); 100 | return &stack_.back(); 101 | } 102 | 103 | void LexicalEnvStack::Pop() { 104 | if (stack_.empty()) { 105 | throw std::runtime_error("Cannot pop from empty stack"); 106 | } 107 | stack_.pop_back(); 108 | } 109 | 110 | size_t LexicalEnvStack::Size() const { 111 | return stack_.size(); 112 | } 113 | 114 | bool LexicalEnvStack::Empty() const { 115 | return stack_.empty(); 116 | } 117 | 118 | std::string* LexicalEnvStack::Get(size_t A, size_t B) const { 119 | CheckIndex(A, B); 120 | 121 | size_t actualIndex = stack_.size() - 1 - A; 122 | return stack_[actualIndex].Get(B); 123 | } 124 | 125 | bool LexicalEnvStack::IsSetSafe(size_t A, size_t B) { 126 | if (stack_.empty()) { 127 | return false; 128 | } 129 | 130 | if (A >= stack_.size()) { 131 | return false; 132 | } 133 | 134 | size_t actualIndex = stack_.size() - 1 - A; 135 | if (!stack_[actualIndex].IsValidIndex(B)) { 136 | return false; 137 | } 138 | return true; 139 | } 140 | 141 | void LexicalEnvStack::Set(size_t A, size_t B, std::string* expr) { 142 | CheckIndex(A, B); 143 | 144 | size_t actualIndex = stack_.size() - 1 - A; 145 | stack_[actualIndex].Set(B, expr); 146 | } 147 | 148 | void LexicalEnvStack::SetIndexes(size_t A, std::set indexes) { 149 | CheckStackIndex(A); 150 | 151 | size_t actualIndex = stack_.size() - 1 - A; 152 | stack_[actualIndex].indexes_.insert(indexes.begin(), indexes.end()); 153 | } 154 | 155 | 156 | LexicalEnv& LexicalEnvStack::GetLexicalEnv(size_t A) { 157 | CheckStackIndex(A); 158 | 159 | size_t actualIndex = stack_.size() - 1 - A; 160 | return stack_[actualIndex]; 161 | } 162 | 163 | LexicalEnv& LexicalEnvStack::Top() { 164 | if (stack_.empty()) { 165 | throw std::runtime_error("Stack is empty"); 166 | } 167 | return stack_.back(); 168 | } 169 | 170 | void LexicalEnvStack::Clear() { 171 | stack_.clear(); 172 | } 173 | 174 | void LexicalEnvStack::CheckIndex(size_t A, size_t B) const { 175 | CheckStackIndex(A); 176 | 177 | size_t actualIndex = stack_.size() - 1 - A; 178 | if (!stack_[actualIndex].IsValidIndex(B)) { 179 | throw std::out_of_range("LexicalEnv index B out of range"); 180 | } 181 | } 182 | 183 | void LexicalEnvStack::CheckStackIndex(size_t A) const { 184 | if (stack_.empty()) { 185 | throw std::runtime_error("Stack is empty"); 186 | } 187 | 188 | if (A >= stack_.size()) { 189 | throw std::out_of_range("Stack index A out of range"); 190 | } 191 | } 192 | 193 | 194 | void DealWithGlobalLexicalWaitlist(uint32_t tier, uint32_t index, std::string closure_name, std::vector *globallexical_waitlist){ 195 | for (auto it = globallexical_waitlist->begin(); it != globallexical_waitlist->end(); ) { 196 | auto* waitelement = *it; 197 | 198 | std::cout << "DealWithGlobalLexicalWaitlist: tier: " << tier << " , index: " << index << std::endl; 199 | 200 | if(waitelement->IsSetSafe(tier, index)){ 201 | waitelement->Set(tier, index, new std::string(closure_name)); 202 | } 203 | 204 | if(waitelement->IsFull()){ 205 | it = globallexical_waitlist->erase(it); 206 | }else{ 207 | ++it; 208 | } 209 | } 210 | } 211 | 212 | void MergeMethod2LexicalMap(Inst* inst, std::map bb2lexicalenvstack, 213 | uint32_t source_methodoffset, uint32_t target_methodoffset, std::map>>* method2lexicalmap) { 214 | // merge instance_initializer lexical to current 215 | 216 | auto& tmpmethod2lexicalmap = *(method2lexicalmap); 217 | 218 | auto source_lexicalmap = tmpmethod2lexicalmap.find(source_methodoffset); 219 | if (source_lexicalmap == tmpmethod2lexicalmap.end()) { 220 | HandleError("#MergeMethod2LexicalMap: source key not found"); 221 | return; 222 | } 223 | 224 | auto lexicalenvstack = bb2lexicalenvstack[inst->GetBasicBlock()]; 225 | for (const auto& [tier, source_indexes] : source_lexicalmap->second) { 226 | lexicalenvstack->SetIndexes(tier, source_indexes); 227 | } 228 | 229 | } 230 | 231 | void PrintInnerMethod2LexicalMap(std::map>>* method2lexicalmap, uint32_t methodoffset){ 232 | auto outerIt = method2lexicalmap->find(methodoffset); 233 | if (outerIt == method2lexicalmap->end()) { 234 | std::cerr << "Method offset not found in the map." << std::endl; 235 | return; 236 | } 237 | 238 | const std::map>& innerMap = outerIt->second; 239 | 240 | for (const auto& pair : innerMap) { 241 | uint32_t key = pair.first; 242 | const std::set& vec = pair.second; 243 | 244 | std::cout << "Key: " << key << " Values: "; 245 | for (const auto& value : vec) { 246 | std::cout << value << " "; 247 | } 248 | std::cout << std::endl; 249 | } 250 | } 251 | 252 | 253 | uint32_t SearchStartposForCreatePrivateproperty(Inst *inst, std::map bb2lexicalenvstack, 254 | std::map>>* method2lexicalmap, uint32_t methodoffset){ 255 | 256 | auto lexicalenvstack = bb2lexicalenvstack[inst->GetBasicBlock()]; 257 | auto &toplexicalenv = lexicalenvstack->Top(); 258 | std::set vec(toplexicalenv.indexes_); 259 | 260 | std::vector sorted(vec.begin(), vec.end()); 261 | std::sort(sorted.begin(), sorted.end()); 262 | 263 | for (size_t i = 0; i < sorted.size(); ++i) { 264 | if (i != sorted[i]) { 265 | return i; 266 | } 267 | } 268 | 269 | HandleError("#SearchStartposForCreatePrivateproperty: not found !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); 270 | 271 | return -1; 272 | } 273 | 274 | 275 | void CopyLexicalenvStack(uint32_t methodoffset_, Inst* inst, std::map* method2lexicalenvstack, 276 | std::map bb2lexicalenvstack, std::vector *globallexical_waitlist){ 277 | 278 | if(bb2lexicalenvstack[inst->GetBasicBlock()]->Empty()){ 279 | return; 280 | //HandleError("#CopyLexicalenvStack: source bb2lexicalenvstack is empty"); 281 | } 282 | auto wait_method = new LexicalEnvStack(*(bb2lexicalenvstack[inst->GetBasicBlock()])); 283 | (*method2lexicalenvstack)[methodoffset_] = wait_method; 284 | globallexical_waitlist->push_back(wait_method); 285 | } -------------------------------------------------------------------------------- /scripts/intrinsic_list.txt: -------------------------------------------------------------------------------- 1 | LDUNDEFINED 2 | LDNULL 3 | LDTRUE 4 | LDFALSE 5 | CREATEEMPTYOBJECT 6 | CREATEEMPTYARRAY_IMM8 7 | CREATEARRAYWITHBUFFER_IMM8_ID16 8 | CREATEOBJECTWITHBUFFER_IMM8_ID16 9 | NEWOBJRANGE_IMM8_IMM8_V8 10 | NEWLEXENV_IMM8 11 | ADD2_IMM8_V8 12 | SUB2_IMM8_V8 13 | MUL2_IMM8_V8 14 | DIV2_IMM8_V8 15 | MOD2_IMM8_V8 16 | EQ_IMM8_V8 17 | NOTEQ_IMM8_V8 18 | LESS_IMM8_V8 19 | LESSEQ_IMM8_V8 20 | GREATER_IMM8_V8 21 | GREATEREQ_IMM8_V8 22 | SHL2_IMM8_V8 23 | SHR2_IMM8_V8 24 | ASHR2_IMM8_V8 25 | AND2_IMM8_V8 26 | OR2_IMM8_V8 27 | XOR2_IMM8_V8 28 | EXP_IMM8_V8 29 | TYPEOF_IMM8 30 | TONUMBER_IMM8 31 | TONUMERIC_IMM8 32 | NEG_IMM8 33 | NOT_IMM8 34 | INC_IMM8 35 | DEC_IMM8 36 | ISTRUE 37 | ISFALSE 38 | ISIN_IMM8_V8 39 | INSTANCEOF_IMM8_V8 40 | STRICTNOTEQ_IMM8_V8 41 | STRICTEQ_IMM8_V8 42 | CALLARG0_IMM8 43 | CALLARG1_IMM8_V8 44 | CALLARGS2_IMM8_V8_V8 45 | CALLARGS3_IMM8_V8_V8_V8 46 | CALLTHIS0_IMM8_V8 47 | CALLTHIS1_IMM8_V8_V8 48 | CALLTHIS2_IMM8_V8_V8_V8 49 | CALLTHIS3_IMM8_V8_V8_V8_V8 50 | CALLTHISRANGE_IMM8_IMM8_V8 51 | SUPERCALLTHISRANGE_IMM8_IMM8_V8 52 | DEFINEFUNC_IMM8_ID16_IMM8 53 | DEFINEMETHOD_IMM8_ID16_IMM8 54 | DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 55 | GETNEXTPROPNAME_V8 56 | LDOBJBYVALUE_IMM8_V8 57 | STOBJBYVALUE_IMM8_V8_V8 58 | LDSUPERBYVALUE_IMM8_V8 59 | LDOBJBYINDEX_IMM8_IMM16 60 | STOBJBYINDEX_IMM8_V8_IMM16 61 | LDLEXVAR_IMM4_IMM4 62 | STLEXVAR_IMM4_IMM4 63 | LDA_STR_ID16 64 | TRYLDGLOBALBYNAME_IMM8_ID16 65 | TRYSTGLOBALBYNAME_IMM8_ID16 66 | LDGLOBALVAR_IMM16_ID16 67 | LDOBJBYNAME_IMM8_ID16 68 | STOBJBYNAME_IMM8_ID16_V8 69 | MOV_V4_V4 70 | MOV_V8_V8 71 | LDSUPERBYNAME_IMM8_ID16 72 | STCONSTTOGLOBALRECORD_IMM16_ID16 73 | STTOGLOBALRECORD_IMM16_ID16 74 | LDTHISBYNAME_IMM8_ID16 75 | STTHISBYNAME_IMM8_ID16 76 | LDTHISBYVALUE_IMM8 77 | STTHISBYVALUE_IMM8_V8 78 | JMP_IMM8 79 | JMP_IMM16 80 | JEQZ_IMM8 81 | JEQZ_IMM16 82 | JNEZ_IMM8 83 | JSTRICTEQZ_IMM8 84 | JNSTRICTEQZ_IMM8 85 | JEQNULL_IMM8 86 | JNENULL_IMM8 87 | JSTRICTEQNULL_IMM8 88 | JNSTRICTEQNULL_IMM8 89 | JEQUNDEFINED_IMM8 90 | JNEUNDEFINED_IMM8 91 | JSTRICTEQUNDEFINED_IMM8 92 | JNSTRICTEQUNDEFINED_IMM8 93 | JEQ_V8_IMM8 94 | JNE_V8_IMM8 95 | JSTRICTEQ_V8_IMM8 96 | JNSTRICTEQ_V8_IMM8 97 | LDA_V8 98 | STA_V8 99 | LDAI_IMM32 100 | FLDAI_IMM64 101 | RETURN 102 | RETURNUNDEFINED 103 | GETPROPITERATOR 104 | GETITERATOR_IMM8 105 | CLOSEITERATOR_IMM8_V8 106 | POPLEXENV 107 | LDNAN 108 | LDINFINITY 109 | GETUNMAPPEDARGS 110 | LDGLOBAL 111 | LDNEWTARGET 112 | LDTHIS 113 | LDHOLE 114 | CREATEREGEXPWITHLITERAL_IMM8_ID16_IMM8 115 | CREATEREGEXPWITHLITERAL_IMM16_ID16_IMM8 116 | CALLRANGE_IMM8_IMM8_V8 117 | DEFINEFUNC_IMM16_ID16_IMM8 118 | DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 119 | GETTEMPLATEOBJECT_IMM8 120 | SETOBJECTWITHPROTO_IMM8_V8 121 | STOWNBYVALUE_IMM8_V8_V8 122 | STOWNBYINDEX_IMM8_V8_IMM16 123 | STOWNBYNAME_IMM8_ID16_V8 124 | GETMODULENAMESPACE_IMM8 125 | STMODULEVAR_IMM8 126 | LDLOCALMODULEVAR_IMM8 127 | LDEXTERNALMODULEVAR_IMM8 128 | STGLOBALVAR_IMM16_ID16 129 | CREATEEMPTYARRAY_IMM16 130 | CREATEARRAYWITHBUFFER_IMM16_ID16 131 | CREATEOBJECTWITHBUFFER_IMM16_ID16 132 | NEWOBJRANGE_IMM16_IMM8_V8 133 | TYPEOF_IMM16 134 | LDOBJBYVALUE_IMM16_V8 135 | STOBJBYVALUE_IMM16_V8_V8 136 | LDSUPERBYVALUE_IMM16_V8 137 | LDOBJBYINDEX_IMM16_IMM16 138 | STOBJBYINDEX_IMM16_V8_IMM16 139 | LDLEXVAR_IMM8_IMM8 140 | STLEXVAR_IMM8_IMM8 141 | TRYLDGLOBALBYNAME_IMM16_ID16 142 | TRYSTGLOBALBYNAME_IMM16_ID16 143 | STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8 144 | MOV_V16_V16 145 | LDOBJBYNAME_IMM16_ID16 146 | STOBJBYNAME_IMM16_ID16_V8 147 | LDSUPERBYNAME_IMM16_ID16 148 | LDTHISBYNAME_IMM16_ID16 149 | STTHISBYNAME_IMM16_ID16 150 | LDTHISBYVALUE_IMM16 151 | STTHISBYVALUE_IMM16_V8 152 | ASYNCGENERATORREJECT_V8 153 | JMP_IMM32 154 | STOWNBYVALUEWITHNAMESET_IMM8_V8_V8 155 | JEQZ_IMM32 156 | JNEZ_IMM16 157 | JNEZ_IMM32 158 | JSTRICTEQZ_IMM16 159 | JNSTRICTEQZ_IMM16 160 | JEQNULL_IMM16 161 | JNENULL_IMM16 162 | JSTRICTEQNULL_IMM16 163 | JNSTRICTEQNULL_IMM16 164 | JEQUNDEFINED_IMM16 165 | JNEUNDEFINED_IMM16 166 | JSTRICTEQUNDEFINED_IMM16 167 | JNSTRICTEQUNDEFINED_IMM16 168 | JEQ_V8_IMM16 169 | JNE_V8_IMM16 170 | JSTRICTEQ_V8_IMM16 171 | JNSTRICTEQ_V8_IMM16 172 | GETITERATOR_IMM16 173 | CLOSEITERATOR_IMM16_V8 174 | LDSYMBOL 175 | ASYNCFUNCTIONENTER 176 | LDFUNCTION 177 | DEBUGGER 178 | CREATEGENERATOROBJ_V8 179 | CREATEITERRESULTOBJ_V8_V8 180 | CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8 181 | NEWOBJAPPLY_IMM8_V8 182 | NEWOBJAPPLY_IMM16_V8 183 | NEWLEXENVWITHNAME_IMM8_ID16 184 | CREATEASYNCGENERATOROBJ_V8 185 | ASYNCGENERATORRESOLVE_V8_V8_V8 186 | SUPERCALLSPREAD_IMM8_V8 187 | APPLY_IMM8_V8_V8 188 | SUPERCALLARROWRANGE_IMM8_IMM8_V8 189 | DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8 190 | DYNAMICIMPORT 191 | DEFINEMETHOD_IMM16_ID16_IMM8 192 | RESUMEGENERATOR 193 | GETRESUMEMODE 194 | GETTEMPLATEOBJECT_IMM16 195 | DELOBJPROP_V8 196 | SUSPENDGENERATOR_V8 197 | ASYNCFUNCTIONAWAITUNCAUGHT_V8 198 | COPYDATAPROPERTIES_V8 199 | STARRAYSPREAD_V8_V8 200 | SETOBJECTWITHPROTO_IMM16_V8 201 | STOWNBYVALUE_IMM16_V8_V8 202 | STSUPERBYVALUE_IMM8_V8_V8 203 | STSUPERBYVALUE_IMM16_V8_V8 204 | STOWNBYINDEX_IMM16_V8_IMM16 205 | STOWNBYNAME_IMM16_ID16_V8 206 | ASYNCFUNCTIONRESOLVE_V8 207 | ASYNCFUNCTIONREJECT_V8 208 | COPYRESTARGS_IMM8 209 | STSUPERBYNAME_IMM8_ID16_V8 210 | STSUPERBYNAME_IMM16_ID16_V8 211 | STOWNBYVALUEWITHNAMESET_IMM16_V8_V8 212 | LDBIGINT_ID16 213 | STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8 214 | NOP 215 | SETGENERATORSTATE_IMM8 216 | GETASYNCITERATOR_IMM8 217 | LDPRIVATEPROPERTY_IMM8_IMM16_IMM16 218 | STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8 219 | TESTIN_IMM8_IMM16_IMM16 220 | DEFINEFIELDBYNAME_IMM8_ID16_V8 221 | DEFINEPROPERTYBYNAME_IMM8_ID16_V8 222 | CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE 223 | WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8 224 | THROW_PREF_NONE 225 | CALLRUNTIME_DEFINEFIELDBYVALUE_PREF_IMM8_V8_V8 226 | WIDE_NEWOBJRANGE_PREF_IMM16_V8 227 | THROW_NOTEXISTS_PREF_NONE 228 | CALLRUNTIME_DEFINEFIELDBYINDEX_PREF_IMM8_IMM32_V8 229 | WIDE_NEWLEXENV_PREF_IMM16 230 | THROW_PATTERNNONCOERCIBLE_PREF_NONE 231 | CALLRUNTIME_TOPROPERTYKEY_PREF_NONE 232 | WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16 233 | THROW_DELETESUPERPROPERTY_PREF_NONE 234 | CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16 235 | WIDE_CALLRANGE_PREF_IMM16_V8 236 | THROW_CONSTASSIGNMENT_PREF_V8 237 | CALLRUNTIME_DEFINEPRIVATEPROPERTY_PREF_IMM8_IMM16_IMM16_V8 238 | WIDE_CALLTHISRANGE_PREF_IMM16_V8 239 | THROW_IFNOTOBJECT_PREF_V8 240 | CALLRUNTIME_CALLINIT_PREF_IMM8_V8 241 | WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8 242 | THROW_UNDEFINEDIFHOLE_PREF_V8_V8 243 | CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8 244 | WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8 245 | THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8 246 | CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16 247 | WIDE_LDOBJBYINDEX_PREF_IMM32 248 | THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16 249 | CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8 250 | WIDE_STOBJBYINDEX_PREF_V8_IMM32 251 | THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16 252 | CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16 253 | WIDE_STOWNBYINDEX_PREF_V8_IMM32 254 | CALLRUNTIME_NEWSENDABLEENV_PREF_IMM8 255 | WIDE_COPYRESTARGS_PREF_IMM16 256 | CALLRUNTIME_WIDENEWSENDABLEENV_PREF_IMM16 257 | WIDE_LDLEXVAR_PREF_IMM16_IMM16 258 | CALLRUNTIME_STSENDABLEVAR_PREF_IMM4_IMM4 259 | WIDE_STLEXVAR_PREF_IMM16_IMM16 260 | CALLRUNTIME_STSENDABLEVAR_PREF_IMM8_IMM8 261 | WIDE_GETMODULENAMESPACE_PREF_IMM16 262 | CALLRUNTIME_WIDESTSENDABLEVAR_PREF_IMM16_IMM16 263 | WIDE_STMODULEVAR_PREF_IMM16 264 | CALLRUNTIME_LDSENDABLEVAR_PREF_IMM4_IMM4 265 | WIDE_LDLOCALMODULEVAR_PREF_IMM16 266 | CALLRUNTIME_LDSENDABLEVAR_PREF_IMM8_IMM8 267 | WIDE_LDEXTERNALMODULEVAR_PREF_IMM16 268 | CALLRUNTIME_WIDELDSENDABLEVAR_PREF_IMM16_IMM16 269 | WIDE_LDPATCHVAR_PREF_IMM16 270 | CALLRUNTIME_ISTRUE_PREF_IMM8 271 | WIDE_STPATCHVAR_PREF_IMM16 272 | CALLRUNTIME_ISFALSE_PREF_IMM8 273 | CALLRUNTIME_LDLAZYMODULEVAR_PREF_IMM8 274 | CALLRUNTIME_WIDELDLAZYMODULEVAR_PREF_IMM16 275 | CALLRUNTIME_LDLAZYSENDABLEMODULEVAR_PREF_IMM8 276 | CALLRUNTIME_WIDELDLAZYSENDABLEMODULEVAR_PREF_IMM16 277 | CALLRUNTIME_SUPERCALLFORWARDALLARGS_PREF_V8 278 | CALLRUNTIME_LDSENDABLELOCALMODULEVAR_PREF_IMM8 279 | CALLRUNTIME_WIDELDSENDABLELOCALMODULEVAR_PREF_IMM16 280 | DEPRECATED_LDLEXENV_PREF_NONE 281 | DEPRECATED_POPLEXENV_PREF_NONE 282 | DEPRECATED_GETITERATORNEXT_PREF_V8_V8 283 | DEPRECATED_CREATEARRAYWITHBUFFER_PREF_IMM16 284 | DEPRECATED_CREATEOBJECTWITHBUFFER_PREF_IMM16 285 | DEPRECATED_TONUMBER_PREF_V8 286 | DEPRECATED_TONUMERIC_PREF_V8 287 | DEPRECATED_NEG_PREF_V8 288 | DEPRECATED_NOT_PREF_V8 289 | DEPRECATED_INC_PREF_V8 290 | DEPRECATED_DEC_PREF_V8 291 | DEPRECATED_CALLARG0_PREF_V8 292 | DEPRECATED_CALLARG1_PREF_V8_V8 293 | DEPRECATED_CALLARGS2_PREF_V8_V8_V8 294 | DEPRECATED_CALLARGS3_PREF_V8_V8_V8_V8 295 | DEPRECATED_CALLRANGE_PREF_IMM16_V8 296 | DEPRECATED_CALLSPREAD_PREF_V8_V8_V8 297 | DEPRECATED_CALLTHISRANGE_PREF_IMM16_V8 298 | DEPRECATED_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8 299 | DEPRECATED_RESUMEGENERATOR_PREF_V8 300 | DEPRECATED_GETRESUMEMODE_PREF_V8 301 | DEPRECATED_GETTEMPLATEOBJECT_PREF_V8 302 | DEPRECATED_DELOBJPROP_PREF_V8_V8 303 | DEPRECATED_SUSPENDGENERATOR_PREF_V8_V8 304 | DEPRECATED_ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8 305 | DEPRECATED_COPYDATAPROPERTIES_PREF_V8_V8 306 | DEPRECATED_SETOBJECTWITHPROTO_PREF_V8_V8 307 | DEPRECATED_LDOBJBYVALUE_PREF_V8_V8 308 | DEPRECATED_LDSUPERBYVALUE_PREF_V8_V8 309 | DEPRECATED_LDOBJBYINDEX_PREF_V8_IMM32 310 | DEPRECATED_ASYNCFUNCTIONRESOLVE_PREF_V8_V8_V8 311 | DEPRECATED_ASYNCFUNCTIONREJECT_PREF_V8_V8_V8 312 | DEPRECATED_STLEXVAR_PREF_IMM4_IMM4_V8 313 | DEPRECATED_STLEXVAR_PREF_IMM8_IMM8_V8 314 | DEPRECATED_STLEXVAR_PREF_IMM16_IMM16_V8 315 | DEPRECATED_GETMODULENAMESPACE_PREF_ID32 316 | DEPRECATED_STMODULEVAR_PREF_ID32 317 | DEPRECATED_LDOBJBYNAME_PREF_ID32_V8 318 | DEPRECATED_LDSUPERBYNAME_PREF_ID32_V8 319 | DEPRECATED_LDMODULEVAR_PREF_ID32_IMM8 320 | DEPRECATED_STCONSTTOGLOBALRECORD_PREF_ID32 321 | DEPRECATED_STLETTOGLOBALRECORD_PREF_ID32 322 | DEPRECATED_STCLASSTOGLOBALRECORD_PREF_ID32 323 | DEPRECATED_LDHOMEOBJECT_PREF_NONE 324 | DEPRECATED_CREATEOBJECTHAVINGMETHOD_PREF_IMM16 325 | DEPRECATED_DYNAMICIMPORT_PREF_V8 326 | DEPRECATED_ASYNCGENERATORREJECT_PREF_V8_V8 327 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | We developed the HarmonyOS NEXT decompilation tool named arkdecompiler, which takes Panda Binary File as input, parses Panda Bytecode, and then translates it into Panda IR. After having IR, we can do various analyses. Based on IR, we reversely construct the native arkTS AST tree, and then we traverse the AST tree and translate it into native arkTS source code. 3 | 4 | 5 | 6 | - 2025.Q3: [2025 Black Hat, USA](https://www.blackhat.com/us-25/arsenal/schedule/index.html#decompiler-for-harmonyos-next-45569) 7 | - 2026.Q1: Support all instructions and program structures 8 | 9 | # Installation 10 | ## Tested platform 11 | Ubuntu 18.04 12 | 13 | In the future we will adapt to other development platforms such as (windows, macOS) and add a GUI. 14 | ## Prepare enviroment 15 | ```bash 16 | mkdir harmonyos 17 | cd harmonyos 18 | run scripts/prepare.sh 19 | ``` 20 | 21 | ## Clone arkdecompiler in harmonyos 22 | ```bash 23 | git clone https://github.com/jd-opensource/arkdecompiler.git 24 | ``` 25 | 26 | 27 | ## Apply patch in harmonyos/arkcompiler/runtime_core 28 | ```bash 29 | git apply --check *.patch 30 | ``` 31 | 32 | 33 | ## Build & Run 34 | ```bash 35 | ./build.sh 36 | 37 | ``` 38 | 39 | ## Usage 40 | ## Prepare demo.ts 41 | refer `tests` directory 42 | 43 | ### Run 44 | ./run.sh 45 | 46 | ### detailed description 47 | - binary executable is **xabc**, 48 | - default input file is:**demo.abc** 49 | - default output file is:**arkdemo.ts** 50 | 51 | 52 | ## Demo 53 | ### Decompile bytecode to arkTS 54 | ![demo](demo.png) 55 | 56 | ### AST 57 | ``` 58 | { 59 | "type": "Program", 60 | "statements": [ 61 | { 62 | "type": "ExpressionStatement", 63 | "expression": { 64 | "type": "AssignmentExpression", 65 | "operator": "=", 66 | "left": { 67 | "type": "Identifier", 68 | "name": "v254", 69 | "loc": { 70 | "start": { 71 | "line": 1, 72 | "column": 1 73 | }, 74 | "end": { 75 | "line": 1, 76 | "column": 1 77 | } 78 | } 79 | }, 80 | "right": { 81 | "type": "Identifier", 82 | "name": "undefined", 83 | "loc": { 84 | "start": { 85 | "line": 1, 86 | "column": 1 87 | }, 88 | "end": { 89 | "line": 1, 90 | "column": 1 91 | } 92 | } 93 | }, 94 | "loc": { 95 | "start": { 96 | "line": 1, 97 | "column": 1 98 | }, 99 | "end": { 100 | "line": 1, 101 | "column": 1 102 | } 103 | } 104 | }, 105 | "loc": { 106 | "start": { 107 | "line": 1, 108 | "column": 1 109 | }, 110 | "end": { 111 | "line": 1, 112 | "column": 1 113 | } 114 | } 115 | }, 116 | { 117 | "type": "ExpressionStatement", 118 | "expression": { 119 | "type": "AssignmentExpression", 120 | "operator": "=", 121 | "left": { 122 | "type": "Identifier", 123 | "name": "c", 124 | "loc": { 125 | "start": { 126 | "line": 1, 127 | "column": 1 128 | }, 129 | "end": { 130 | "line": 1, 131 | "column": 1 132 | } 133 | } 134 | }, 135 | "right": { 136 | "type": "Identifier", 137 | "name": "v254", 138 | "loc": { 139 | "start": { 140 | "line": 1, 141 | "column": 1 142 | }, 143 | "end": { 144 | "line": 1, 145 | "column": 1 146 | } 147 | } 148 | }, 149 | "loc": { 150 | "start": { 151 | "line": 1, 152 | "column": 1 153 | }, 154 | "end": { 155 | "line": 1, 156 | "column": 1 157 | } 158 | } 159 | }, 160 | "loc": { 161 | "start": { 162 | "line": 1, 163 | "column": 1 164 | }, 165 | "end": { 166 | "line": 1, 167 | "column": 1 168 | } 169 | } 170 | }, 171 | { 172 | "type": "ExpressionStatement", 173 | "expression": { 174 | "type": "AssignmentExpression", 175 | "operator": "=", 176 | "left": { 177 | "type": "Identifier", 178 | "name": "v0", 179 | "loc": { 180 | "start": { 181 | "line": 1, 182 | "column": 1 183 | }, 184 | "end": { 185 | "line": 1, 186 | "column": 1 187 | } 188 | } 189 | }, 190 | "right": { 191 | "type": "NumberLiteral", 192 | "value": 1, 193 | "loc": { 194 | "start": { 195 | "line": 1, 196 | "column": 1 197 | }, 198 | "end": { 199 | "line": 1, 200 | "column": 1 201 | } 202 | } 203 | }, 204 | "loc": { 205 | "start": { 206 | "line": 1, 207 | "column": 1 208 | }, 209 | "end": { 210 | "line": 1, 211 | "column": 1 212 | } 213 | } 214 | }, 215 | "loc": { 216 | "start": { 217 | "line": 1, 218 | "column": 1 219 | }, 220 | "end": { 221 | "line": 1, 222 | "column": 1 223 | } 224 | } 225 | }, 226 | { 227 | "type": "ExpressionStatement", 228 | "expression": { 229 | "type": "AssignmentExpression", 230 | "operator": "=", 231 | "left": { 232 | "type": "Identifier", 233 | "name": "v254", 234 | "loc": { 235 | "start": { 236 | "line": 1, 237 | "column": 1 238 | }, 239 | "end": { 240 | "line": 1, 241 | "column": 1 242 | } 243 | } 244 | }, 245 | "right": { 246 | "type": "BinaryExpression", 247 | "operator": "+", 248 | "left": { 249 | "type": "NumberLiteral", 250 | "value": 1, 251 | "loc": { 252 | "start": { 253 | "line": 1, 254 | "column": 1 255 | }, 256 | "end": { 257 | "line": 1, 258 | "column": 1 259 | } 260 | } 261 | }, 262 | "right": { 263 | "type": "Identifier", 264 | "name": "v0", 265 | "loc": { 266 | "start": { 267 | "line": 1, 268 | "column": 1 269 | }, 270 | "end": { 271 | "line": 1, 272 | "column": 1 273 | } 274 | } 275 | }, 276 | "loc": { 277 | "start": { 278 | "line": 1, 279 | "column": 1 280 | }, 281 | "end": { 282 | "line": 1, 283 | "column": 1 284 | } 285 | } 286 | }, 287 | "loc": { 288 | "start": { 289 | "line": 1, 290 | "column": 1 291 | }, 292 | "end": { 293 | "line": 1, 294 | "column": 1 295 | } 296 | } 297 | }, 298 | "loc": { 299 | "start": { 300 | "line": 1, 301 | "column": 1 302 | }, 303 | "end": { 304 | "line": 1, 305 | "column": 1 306 | } 307 | } 308 | }, 309 | { 310 | "type": "ExpressionStatement", 311 | "expression": { 312 | "type": "AssignmentExpression", 313 | "operator": "=", 314 | "left": { 315 | "type": "Identifier", 316 | "name": "c", 317 | "loc": { 318 | "start": { 319 | "line": 1, 320 | "column": 1 321 | }, 322 | "end": { 323 | "line": 1, 324 | "column": 1 325 | } 326 | } 327 | }, 328 | "right": { 329 | "type": "Identifier", 330 | "name": "v254", 331 | "loc": { 332 | "start": { 333 | "line": 1, 334 | "column": 1 335 | }, 336 | "end": { 337 | "line": 1, 338 | "column": 1 339 | } 340 | } 341 | }, 342 | "loc": { 343 | "start": { 344 | "line": 1, 345 | "column": 1 346 | }, 347 | "end": { 348 | "line": 1, 349 | "column": 1 350 | } 351 | } 352 | }, 353 | "loc": { 354 | "start": { 355 | "line": 1, 356 | "column": 1 357 | }, 358 | "end": { 359 | "line": 1, 360 | "column": 1 361 | } 362 | } 363 | }, 364 | { 365 | "type": "ExpressionStatement", 366 | "expression": { 367 | "type": "AssignmentExpression", 368 | "operator": "=", 369 | "left": { 370 | "type": "Identifier", 371 | "name": "v254", 372 | "loc": { 373 | "start": { 374 | "line": 1, 375 | "column": 1 376 | }, 377 | "end": { 378 | "line": 1, 379 | "column": 1 380 | } 381 | } 382 | }, 383 | "right": { 384 | "type": "Identifier", 385 | "name": "undefined", 386 | "loc": { 387 | "start": { 388 | "line": 1, 389 | "column": 1 390 | }, 391 | "end": { 392 | "line": 1, 393 | "column": 1 394 | } 395 | } 396 | }, 397 | "loc": { 398 | "start": { 399 | "line": 1, 400 | "column": 1 401 | }, 402 | "end": { 403 | "line": 1, 404 | "column": 1 405 | } 406 | } 407 | }, 408 | "loc": { 409 | "start": { 410 | "line": 1, 411 | "column": 1 412 | }, 413 | "end": { 414 | "line": 1, 415 | "column": 1 416 | } 417 | } 418 | }, 419 | { 420 | "type": "ReturnStatement", 421 | "argument": { 422 | "type": "Identifier", 423 | "name": "undefined", 424 | "loc": { 425 | "start": { 426 | "line": 1, 427 | "column": 1 428 | }, 429 | "end": { 430 | "line": 1, 431 | "column": 1 432 | } 433 | } 434 | }, 435 | "loc": { 436 | "start": { 437 | "line": 1, 438 | "column": 1 439 | }, 440 | "end": { 441 | "line": 1, 442 | "column": 1 443 | } 444 | } 445 | } 446 | ], 447 | "loc": { 448 | "start": { 449 | "line": 1, 450 | "column": 1 451 | }, 452 | "end": { 453 | "line": 1, 454 | "column": 1 455 | } 456 | } 457 | } 458 | 459 | ``` 460 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /modulevar.cpp: -------------------------------------------------------------------------------- 1 | #include "modulevar.h" 2 | 3 | std::string GetStringByOffset(std::unique_ptr& file_, uint32_t offset) 4 | { 5 | const auto sd = file_->GetStringData(panda_file::File::EntityId(offset)); 6 | return std::string(utf::Mutf8AsCString(sd.data)); 7 | } 8 | 9 | bool IsValidOffset(std::unique_ptr& file_, uint32_t offset) 10 | { 11 | return panda_file::File::EntityId(offset).IsValid() && offset < file_->GetHeader()->file_size; 12 | } 13 | 14 | void AddImportAst(panda::es2panda::parser::Program *parser_program, std::string imported_name, std::string local_name, std::string module_name){ 15 | auto program_ast = parser_program->Ast(); 16 | auto program_statements = program_ast->Statements(); 17 | 18 | panda::es2panda::util::StringView imported_name_view = panda::es2panda::util::StringView(*new std::string(imported_name)); 19 | auto imported_nameid = AllocNode(parser_program, imported_name_view); 20 | 21 | panda::es2panda::util::StringView local_name_strview = panda::es2panda::util::StringView(*new std::string(local_name)); 22 | auto local_nameid = AllocNode(parser_program, local_name_strview); 23 | 24 | auto importspefic = AllocNode(parser_program, imported_nameid, local_nameid, false, false); 25 | 26 | ArenaVector specifiers(parser_program->Allocator()->Adapter()); 27 | specifiers.push_back(importspefic); 28 | 29 | 30 | std::string* source_str_ptr = new std::string(module_name); 31 | es2panda::util::StringView literal_strview(*source_str_ptr); 32 | auto source = AllocNode(parser_program, literal_strview); 33 | auto *importDeclaration = AllocNode(parser_program, source, std::move(specifiers), nullptr, false, false); 34 | program_ast->AddStatementAtPos(program_statements.size(), importDeclaration); 35 | } 36 | 37 | void AddExportAstAll(panda::es2panda::parser::Program *parser_program, std::string module_name){ 38 | auto program_ast = parser_program->Ast(); 39 | auto program_statements = program_ast->Statements(); 40 | 41 | panda::es2panda::util::StringView local_name_strview = panda::es2panda::util::StringView(*new std::string("*")); 42 | auto local_nameid = AllocNode(parser_program, local_name_strview); 43 | 44 | 45 | std::string* source_str_ptr = new std::string(module_name); 46 | es2panda::util::StringView literal_strview(*source_str_ptr); 47 | auto source = AllocNode(parser_program, literal_strview); 48 | 49 | auto *export_all = AllocNode(parser_program, source, local_nameid, nullptr); 50 | program_ast->AddStatementAtPos(program_statements.size(), export_all); 51 | } 52 | 53 | void AddExportAstNamed(panda::es2panda::parser::Program *parser_program, std::string import_name, std::string export_name, std::string module_name){ 54 | auto program_ast = parser_program->Ast(); 55 | auto program_statements = program_ast->Statements(); 56 | 57 | panda::es2panda::util::StringView import_name_view = panda::es2panda::util::StringView(*new std::string(import_name)); 58 | auto import_nameid = AllocNode(parser_program, import_name_view); 59 | 60 | panda::es2panda::util::StringView export_name_strview = panda::es2panda::util::StringView(*new std::string(export_name)); 61 | auto export_nameid = AllocNode(parser_program, export_name_strview); 62 | 63 | auto exportspefic = AllocNode(parser_program, import_nameid, export_nameid, false); 64 | 65 | ArenaVector specifiers(parser_program->Allocator()->Adapter()); 66 | specifiers.push_back(exportspefic); 67 | 68 | 69 | std::string* source_str_ptr = new std::string(module_name); 70 | es2panda::util::StringView literal_strview(*source_str_ptr); 71 | auto source = AllocNode(parser_program, literal_strview); 72 | auto *exportDeclaration = AllocNode(parser_program, source, std::move(specifiers), nullptr, false); 73 | program_ast->AddStatementAtPos(program_statements.size(), exportDeclaration); 74 | } 75 | 76 | void AddExportAst(panda::es2panda::parser::Program *parser_program, std::string local_name, std::string export_name){ 77 | auto program_ast = parser_program->Ast(); 78 | auto program_statements = program_ast->Statements(); 79 | 80 | panda::es2panda::util::StringView local_name_strview = panda::es2panda::util::StringView(*new std::string(local_name)); 81 | auto local_nameid = AllocNode(parser_program, local_name_strview); 82 | 83 | panda::es2panda::util::StringView export_name_strview = panda::es2panda::util::StringView(*new std::string(export_name)); 84 | auto export_nameid = AllocNode(parser_program, export_name_strview); 85 | 86 | auto *exportast = AllocNode(parser_program, local_nameid, export_nameid, false); 87 | program_ast->AddStatementAtPos(program_statements.size(), exportast); 88 | 89 | } 90 | 91 | void GetModuleLiteralArray(std::unique_ptr& file_, panda_file::File::EntityId &module_id, panda::disasm::Disassembler& disasm, 92 | panda::es2panda::parser::Program *parser_program, std::map> &index2namespaces, 93 | std::vector& localnamespaces) 94 | { 95 | // AddImportAst(parser_program, "a", "b", "./module_foo1"); // mock refs 96 | 97 | std::map index2importmodule; 98 | std::map importmodule2index; 99 | 100 | std::map> index2importmaps; 101 | std::vector> exportmaps_arrays; 102 | 103 | panda_file::ModuleDataAccessor mda(*file_, module_id); 104 | const std::vector &request_modules_offset = mda.getRequestModules(); 105 | std::vector module_literal_array; 106 | 107 | for (size_t index = 0; index < request_modules_offset.size(); ++index) { 108 | index2importmodule[index] = GetStringByOffset(file_, request_modules_offset[index]); 109 | importmodule2index[GetStringByOffset(file_, request_modules_offset[index])] = index; 110 | 111 | index2namespaces[index] = std::vector(); 112 | } 113 | 114 | mda.EnumerateModuleRecord([&](panda_file::ModuleTag tag, uint32_t export_name_offset, uint32_t request_module_idx, 115 | uint32_t import_name_offset, uint32_t local_name_offset) { 116 | 117 | std::map curmaps; 118 | 119 | std::stringstream ss; 120 | if (tag == panda_file::ModuleTag::REGULAR_IMPORT || 121 | tag == panda_file::ModuleTag::NAMESPACE_IMPORT || tag == panda_file::ModuleTag::LOCAL_EXPORT) { 122 | if (!disasm.IsValidOffset(local_name_offset)) { 123 | LOG(ERROR, DISASSEMBLER) << "Get invalid local name offset!" << std::endl; 124 | return; 125 | } 126 | curmaps["local_name"] = GetStringByOffset(file_, local_name_offset); 127 | 128 | ss << ", local_name: " << GetStringByOffset(file_, local_name_offset); 129 | } 130 | if (tag == panda_file::ModuleTag::LOCAL_EXPORT || tag == panda_file::ModuleTag::INDIRECT_EXPORT) { 131 | if (!IsValidOffset(file_, export_name_offset)) { 132 | LOG(ERROR, DISASSEMBLER) << "Get invalid export name offset!" << std::endl; 133 | return; 134 | } 135 | curmaps["export_name"] = GetStringByOffset(file_, export_name_offset); 136 | 137 | ss << ", export_name: " << GetStringByOffset(file_, export_name_offset); 138 | } 139 | if (tag == panda_file::ModuleTag::REGULAR_IMPORT || tag == panda_file::ModuleTag::INDIRECT_EXPORT) { 140 | if (!IsValidOffset(file_, import_name_offset)) { 141 | LOG(ERROR, DISASSEMBLER) << "Get invalid import name offset!" << std::endl; 142 | return; 143 | } 144 | curmaps["import_name"] = GetStringByOffset(file_, import_name_offset); 145 | 146 | ss << ", import_name: " << GetStringByOffset(file_, import_name_offset); 147 | } 148 | if (tag != panda_file::ModuleTag::LOCAL_EXPORT) { 149 | if (request_module_idx >= request_modules_offset.size() || 150 | !IsValidOffset(file_, request_modules_offset[request_module_idx])) { 151 | LOG(ERROR, DISASSEMBLER) << "Get invalid request module offset!" << std::endl; 152 | return; 153 | } 154 | curmaps["module_request"] = GetStringByOffset(file_, request_modules_offset[request_module_idx]); 155 | 156 | ss << ", module_request: " << GetStringByOffset(file_, request_modules_offset[request_module_idx]); 157 | } 158 | 159 | 160 | if(tag == panda_file::ModuleTag::REGULAR_IMPORT || tag == panda_file::ModuleTag::NAMESPACE_IMPORT){ 161 | ss << ", IMPORT "; 162 | auto module_request_name = curmaps["module_request"]; 163 | auto index = importmodule2index[module_request_name]; 164 | 165 | index2importmaps[index] = curmaps; 166 | if(curmaps.count("import_name") > 0){ 167 | AddImportAst(parser_program, curmaps["import_name"], curmaps["local_name"], curmaps["module_request"]); 168 | }else{ 169 | AddImportAst(parser_program, "*", curmaps["local_name"], curmaps["module_request"]); 170 | } 171 | index2namespaces[importmodule2index[curmaps["module_request"]]].push_back(curmaps["local_name"]); 172 | 173 | localnamespaces.push_back(curmaps["local_name"]); 174 | }else{ 175 | ss << ", EXPORT "; 176 | exportmaps_arrays.push_back(curmaps); 177 | // std::cout << curmaps.count("export_name") << " , " << curmaps.count("import_name") << " , " << curmaps.count("local_name") << " , " << curmaps.count("module_request") << std::endl; 178 | if(curmaps.count("export_name") == 0 && curmaps.count("local_name") == 0){ 179 | // ExportAllDeclaration 180 | AddExportAstAll(parser_program, curmaps["module_request"]); 181 | 182 | }else if(curmaps.count("module_request") == 0){ 183 | // ExportSpecifier 184 | AddExportAst(parser_program, curmaps["local_name"], curmaps["export_name"]); 185 | localnamespaces.push_back(curmaps["local_name"]); 186 | }else{ 187 | // ExportNamedDeclaration 188 | AddExportAstNamed(parser_program, curmaps["import_name"], curmaps["export_name"], curmaps["module_request"]); 189 | localnamespaces.push_back(curmaps["import_name"]); 190 | } 191 | } 192 | 193 | std::cout << ss.str() << std::endl;; 194 | }); 195 | 196 | } 197 | 198 | void ParseModuleVars(std::unique_ptr& file_, pandasm::Program *prog, panda::disasm::Disassembler& disasm, 199 | panda::es2panda::parser::Program *parser_program, std::map>& index2namespaces, 200 | std::vector& localnamespaces){ 201 | 202 | 203 | 204 | if (panda_file::ContainsLiteralArrayInHeader(file_->GetHeader()->version)) { 205 | const auto lit_arrays_id = file_->GetLiteralArraysId(); 206 | 207 | panda_file::LiteralDataAccessor lda(*file_, lit_arrays_id); 208 | size_t num_litarrays = lda.GetLiteralNum(); 209 | 210 | for (size_t index = 0; index < num_litarrays; index++) { 211 | 212 | auto id = lda.GetLiteralArrayId(index); 213 | if (disasm.module_request_phase_literals_.count(id.GetOffset())) { 214 | continue; 215 | } 216 | 217 | if (disasm.IsModuleLiteralOffset(id)) { 218 | GetModuleLiteralArray(file_, id, disasm, parser_program, index2namespaces, localnamespaces); 219 | } 220 | } 221 | }else{ 222 | // release mode 223 | for (const auto &r : prog->record_table) { 224 | auto& record = r.second; 225 | for (const auto &f : record.field_list) { 226 | if (!f.metadata->GetValue().has_value()) { 227 | continue; 228 | } 229 | if (f.type.GetId() == panda_file::Type::TypeId::U32) { 230 | panda_file::File::EntityId module_entity_id(f.metadata->GetValue().value().GetValue()); 231 | if (disasm.IsModuleLiteralOffset(module_entity_id)) { 232 | GetModuleLiteralArray(file_, module_entity_id, disasm, parser_program, index2namespaces, localnamespaces); 233 | } 234 | } 235 | } 236 | 237 | } 238 | 239 | // debug mode 240 | // panda::libpandafile::CollectUtil collect_util; 241 | // std::unordered_set literal_array_ids; 242 | // collect_util.CollectLiteralArray(*file_, literal_array_ids); 243 | // for (uint32_t literal_array_id : literal_array_ids) { 244 | // panda_file::File::EntityId id {literal_array_id}; 245 | // if (disasm.IsModuleLiteralOffset(id)) { 246 | // GetModuleLiteralArray(file_, id, disasm, parser_program, index2namespaces, localnamespaces); 247 | // } 248 | // } 249 | } 250 | 251 | } -------------------------------------------------------------------------------- /xabc.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define PANDA_USE_FUTEX 1 3 | #define PANDA_TARGET_UNIX 1 4 | 5 | #include "astgen.h" 6 | #include "base.h" 7 | #include "arkts.h" 8 | #include "lexicalenv.h" 9 | #include "modulevar.h" 10 | #include "fundepscan.h" 11 | #include "algos.h" 12 | #include "classconstruction.h" 13 | 14 | using namespace std; 15 | using namespace panda; 16 | using namespace bytecodeopt; 17 | 18 | std::string inputFileName = "demo.abc"; 19 | std::string outputFileName = "arkdemo.ts"; 20 | std::string outputAstFileName = "arkdemo.ast"; 21 | 22 | template 23 | constexpr void RunOpts(compiler::Graph *graph) 24 | { 25 | graph->RunPass(); 26 | graph->RunPass(); 27 | } 28 | 29 | template 30 | constexpr void RunOpts(compiler::Graph *graph) 31 | { 32 | RunOpts(graph); 33 | RunOpts(graph); 34 | } 35 | 36 | 37 | static void SetCompilerOptions() 38 | { 39 | compiler::options.SetCompilerUseSafepoint(false); 40 | compiler::options.SetCompilerSupportInitObjectInst(true); 41 | if (!compiler::options.WasSetCompilerMaxBytecodeSize()) { 42 | compiler::options.SetCompilerMaxBytecodeSize(MAX_BYTECODE_SIZE); 43 | } 44 | } 45 | 46 | 47 | static bool SkipFunction(const pandasm::Function &function, const std::string &func_name) 48 | { 49 | if (panda::bytecodeopt::options.WasSetMethodRegex()) { 50 | static std::regex rgx(panda::bytecodeopt::options.GetMethodRegex()); 51 | if (!std::regex_match(func_name, rgx)) { 52 | LOG(INFO, BYTECODE_OPTIMIZER) << "Skip Function " << func_name << ": Function's name doesn't match regex"; 53 | return true; 54 | } 55 | } 56 | 57 | if (panda::bytecodeopt::options.IsSkipMethodsWithEh() && !function.catch_blocks.empty()) { 58 | LOG(INFO, BYTECODE_OPTIMIZER) << "Was not optimized " << func_name << ": Function has catch blocks"; 59 | return true; 60 | } 61 | 62 | if ((function.regs_num + function.GetParamsNum()) > compiler::VIRTUAL_FRAME_SIZE) { 63 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Unable to optimize " << func_name 64 | << ": Function frame size is larger than allowed one"; 65 | return true; 66 | } 67 | return false; 68 | } 69 | 70 | bool DecompileRunOptimizations(compiler::Graph *graph, BytecodeOptIrInterface *iface) 71 | { 72 | constexpr int OPT_LEVEL_0 = 0; 73 | if (panda::bytecodeopt::options.GetOptLevel() == OPT_LEVEL_0) { 74 | return false; 75 | } 76 | 77 | graph->RunPass(); 78 | ASSERT(graph->IsDynamicMethod()); 79 | if (compiler::options.IsCompilerBranchElimination()) { 80 | graph->RunPass(iface); 81 | RunOpts(graph); 82 | } 83 | 84 | RunOpts(graph); 85 | 86 | graph->RunPass(); 87 | graph->RunPass(); 88 | 89 | graph->RunPass(); 90 | if (!RegAlloc(graph)) { 91 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Failed compiler::RegAlloc"; 92 | return false; 93 | } 94 | 95 | graph->RunPass(); 96 | if (!graph->RunPass()) { 97 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Failed RegEncoder"; 98 | return false; 99 | } 100 | 101 | return true; 102 | } 103 | 104 | bool DecompileFunction(pandasm::Program *prog, panda::es2panda::parser::Program *parser_program, 105 | BytecodeOptIrInterface *ir_interface, 106 | const panda_file::MethodDataAccessor &mda, bool is_dynamic, 107 | std::map* method2lexicalenvstack, 108 | std::map* method2sendablelexicalenvstack, 109 | std::map* patchvarspace, 110 | std::map>& index2namespaces, 111 | std::vector& localnamespaces, 112 | std::map> *class2memberfuns, 113 | std::map *method2scriptfunast, 114 | std::map* ctor2classdeclast, 115 | std::set* memberfuncs, 116 | std::map *class2father, 117 | std::map>> *method2lexicalmap, 118 | std::vector* globallexical_waitlist, 119 | std::vector* globalsendablelexical_waitlist, 120 | std::map *raw2newname, 121 | std::map *methodname2offset 122 | ) 123 | { 124 | 125 | ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER}; 126 | ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; 127 | 128 | SetCompilerOptions(); 129 | 130 | auto func_name = ir_interface->GetMethodIdByOffset(mda.GetMethodId().GetOffset() ); 131 | std::cout << std::endl << "[+] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Decompile " << func_name << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< [+]" << std::endl << std::endl; 132 | 133 | auto it = prog->function_table.find(func_name); 134 | if (it == prog->function_table.end()) { 135 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Cannot find function: " << func_name; 136 | return false; 137 | } 138 | 139 | LOG(INFO, BYTECODE_OPTIMIZER) << "Optimizing function: " << func_name; 140 | 141 | auto method_ptr = reinterpret_cast(mda.GetMethodId().GetOffset()); 142 | 143 | panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile()); 144 | auto graph = allocator.New(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter, false, 145 | nullptr, is_dynamic, true); 146 | 147 | 148 | panda::pandasm::Function &function = it->second; 149 | 150 | if (SkipFunction(function, func_name)) { 151 | return false; 152 | } 153 | 154 | 155 | if ((graph == nullptr) || !graph->RunPass()) { 156 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": IR builder failed!"; 157 | std::cout << "Optimizing " << func_name << ": IR builder failed!" << std::endl; 158 | return false; 159 | } 160 | 161 | if (graph->HasIrreducibleLoop()) { 162 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Graph has irreducible loop!"; 163 | std::cout << "Optimizing " << func_name << ": Graph has irreducible loop!" << std::endl; 164 | return false; 165 | } 166 | 167 | if (!DecompileRunOptimizations(graph, ir_interface)) { 168 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Running optimizations failed!"; 169 | std::cout << "Optimizing " << func_name << ": Running optimizations failed!" << std::endl; 170 | return false; 171 | } 172 | 173 | std::ofstream dump_out("logs/" + func_name+ ".ir"); 174 | graph->Dump(&dump_out); 175 | 176 | 177 | if (!graph->RunPass(&function, ir_interface, prog, parser_program, mda.GetMethodId().GetOffset(), method2lexicalenvstack, 178 | method2sendablelexicalenvstack, patchvarspace, std::ref(index2namespaces), 179 | std::ref(localnamespaces), std::ref(class2memberfuns), std::ref(method2scriptfunast), std::ref(ctor2classdeclast), std::ref(memberfuncs), 180 | std::ref(class2father), std::ref(method2lexicalmap), std::ref(globallexical_waitlist), std::ref(globalsendablelexical_waitlist), 181 | std::ref(raw2newname), std::ref(methodname2offset), 182 | RemoveArgumentsOfFunc(func_name))) { 183 | 184 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Code generation failed!"; 185 | 186 | std::cout << "Decompiling " << func_name << ": Code generation failed!" << std::endl; 187 | 188 | return false; 189 | } 190 | 191 | std::cout << std::endl << "[-] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Decompile " << func_name << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< [-]" << std::endl << std::endl; 192 | 193 | return true; 194 | } 195 | 196 | void LogAst(panda::es2panda::parser::Program *parser_program, std::string outputFileName){ 197 | std::cout << "[+] log raw ast start >>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; 198 | std::string res = parser_program->Dump(); 199 | //std::cout << res << std::endl; 200 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << std::endl; 201 | std::ofstream outputFile(outputFileName); 202 | if (!outputFile.is_open()) { 203 | std::cerr << "can't open output file: " << outputFileName << std::endl; 204 | }else{ 205 | outputFile << res; 206 | outputFile.close(); 207 | } 208 | std::cout << "[-] log raw ast end >>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; 209 | } 210 | 211 | void LogArkTS2File(panda::es2panda::parser::Program *parser_program, std::string outputFileName){ 212 | std::cout << "[+] log arkTS start >>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; 213 | auto astsgen = panda::es2panda::ir::ArkTSGen(parser_program->Ast()); 214 | 215 | std::cout << astsgen.Str() << std::endl; 216 | std::cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << std::endl; 217 | std::ofstream outputFile(outputFileName); 218 | if (!outputFile.is_open()) { 219 | std::cerr << "can't open output file: " << outputFileName << std::endl; 220 | }else{ 221 | outputFile << astsgen.Str(); 222 | outputFile.close(); 223 | } 224 | std::cout << "[-] log arkTS end >>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; 225 | } 226 | 227 | 228 | int32_t ScanFunDep(pandasm::Program *prog, panda::disasm::Disassembler& disasm, 229 | BytecodeOptIrInterface *ir_interface, 230 | std::vector>* depedges, 231 | std::map> *class2memberfuns, 232 | std::map>>* method2lexicalmap, 233 | std::set* memberfuncs, 234 | std::map *raw2newname, 235 | std::map *methodname2offset, 236 | const panda_file::MethodDataAccessor &mda, bool is_dynamic) 237 | { 238 | 239 | ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER}; 240 | ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; 241 | 242 | SetCompilerOptions(); 243 | 244 | auto func_name = ir_interface->GetMethodIdByOffset(mda.GetMethodId().GetOffset() ); 245 | std::cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>> " << func_name << " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << std::endl; 246 | auto it = prog->function_table.find(func_name); 247 | if (it == prog->function_table.end()) { 248 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Cannot find function: " << func_name; 249 | return 1; 250 | } 251 | 252 | LOG(INFO, BYTECODE_OPTIMIZER) << "Optimizing function: " << func_name; 253 | 254 | auto method_ptr = reinterpret_cast(mda.GetMethodId().GetOffset()); 255 | 256 | panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile()); 257 | auto graph = allocator.New(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter, false, 258 | nullptr, is_dynamic, true); 259 | 260 | 261 | panda::pandasm::Function &function = it->second; 262 | 263 | if (SkipFunction(function, func_name)) { 264 | return 2; 265 | } 266 | 267 | if ((graph == nullptr) || !graph->RunPass()) { 268 | //LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": IR builder failed!"; 269 | std::cout << "Optimizing " << func_name << ": IR builder failed!" << std::endl; 270 | return 3; 271 | } 272 | 273 | if (graph->HasIrreducibleLoop()) { 274 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Graph has irreducible loop!"; 275 | std::cout << "Optimizing " << func_name << ": Graph has irreducible loop!" << std::endl; 276 | return 4; 277 | } 278 | 279 | if (!DecompileRunOptimizations(graph, ir_interface)) { 280 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Running optimizations failed!"; 281 | std::cout << "Optimizing " << func_name << ": Running optimizations failed!" << std::endl; 282 | return 5; 283 | } 284 | 285 | if (!graph->RunPass(ir_interface, prog, std::ref(disasm), mda.GetMethodId().GetOffset(), depedges, class2memberfuns, method2lexicalmap, memberfuncs, raw2newname, methodname2offset)) { 286 | LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": FuncDep scanning failed!"; 287 | 288 | std::cout << "FuncDep Scanning " << func_name << ": failed!" << std::endl; 289 | 290 | return 6; 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | void ConstructMethodname2offset(panda::disasm::Disassembler& disasm, std::map *methodname2offset){ 297 | for (const auto& pair : disasm.method_name_to_id_) { 298 | std::cout << "##########################################################" << std::endl; 299 | std::cout << "first: " << pair.first << std::endl; 300 | std::cout << "second: " << pair.second << std::endl; 301 | 302 | std::size_t pos = pair.first.find(':'); 303 | if (pos != std::string::npos) { 304 | std::string result = RemoveArgumentsOfFunc(pair.first); 305 | (*methodname2offset)[result] = pair.second.GetOffset(); 306 | } 307 | } 308 | } 309 | 310 | bool DecompilePandaFile(pandasm::Program *prog, BytecodeOptIrInterface *ir_interface, 311 | const std::string &pfile_name, panda::disasm::Disassembler& disasm, bool is_dynamic) 312 | { 313 | auto pfile = panda_file::OpenPandaFile(pfile_name); 314 | if (!pfile) { 315 | LOG(FATAL, BYTECODE_OPTIMIZER) << "Can not open binary file: " << pfile_name; 316 | } 317 | 318 | 319 | bool result = true; 320 | panda::es2panda::parser::Program *parser_program = new panda::es2panda::parser::Program(panda::es2panda::ScriptExtension::TS); 321 | 322 | ArenaVector program_statements(parser_program->Allocator()->Adapter()); 323 | 324 | auto program_ast = AllocNode(parser_program, nullptr, std::move(program_statements)); 325 | 326 | parser_program->SetAst(program_ast); 327 | 328 | std::map method2lexicalenvstack; 329 | std::map method2sendablelexicalenvstack; 330 | 331 | std::map> index2importnamespaces; 332 | 333 | std::map> class2memberfuns; 334 | std::map class2father; 335 | 336 | std::map method2scriptfunast; 337 | 338 | std::map ctor2classdeclast; 339 | 340 | std::set memberfuncs; // all member functions(all classes) 341 | 342 | std::vector localnamespaces; 343 | 344 | std::map raw2newname; 345 | 346 | std::map>> method2lexicalmap; // methodoffset, tier, 347 | 348 | std::vector globallexical_waitlist; 349 | 350 | std::vector globalsendablelexical_waitlist; 351 | 352 | std::map methodname2offset; 353 | 354 | ParseModuleVars(pfile, prog, disasm, parser_program, index2importnamespaces, localnamespaces); 355 | 356 | ConstructMethodname2offset(disasm, &methodname2offset); 357 | 358 | for (uint32_t id : pfile->GetClasses()) { 359 | panda_file::File::EntityId record_id {id}; 360 | if (pfile->IsExternal(record_id)) { 361 | continue; 362 | } 363 | 364 | panda_file::ClassDataAccessor cda {*pfile, record_id}; 365 | std::cout << "classname: " << std::left << std::setw(40) << cda.GetName().data << " , fileds: " << cda.GetFieldsNumber() << " , method: " << cda.GetMethodsNumber() << " interface: " << cda.GetIfacesNumber() << " superclass: " << cda.GetSuperClassId() << std::endl; 366 | } 367 | 368 | for (uint32_t id : pfile->GetClasses()) { 369 | 370 | panda_file::File::EntityId record_id {id}; 371 | 372 | if (pfile->IsExternal(record_id)) { 373 | continue; 374 | } 375 | 376 | panda_file::ClassDataAccessor cda {*pfile, record_id}; 377 | std::vector> depedges; 378 | 379 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 380 | std::set skipfailfuns; // skip ir build functions 381 | cda.EnumerateMethods([prog, &disasm, ir_interface, is_dynamic, &depedges, &class2memberfuns, &method2lexicalmap, &memberfuncs, &raw2newname, &methodname2offset, &skipfailfuns](panda_file::MethodDataAccessor &mda){ 382 | if (!mda.IsExternal()) { 383 | 384 | int32_t res = ScanFunDep(prog, disasm, ir_interface, &depedges, &class2memberfuns, &method2lexicalmap, &memberfuncs, &raw2newname, &methodname2offset, mda, is_dynamic); 385 | if(res == 3 || res == 4){ 386 | skipfailfuns.insert(mda.GetMethodId().GetOffset()); 387 | return; 388 | } 389 | 390 | if(res != 0){ 391 | HandleError("#DecompilePandaFile: fun dep scan failed!"); 392 | } 393 | } 394 | }); 395 | 396 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 397 | auto sorted_methodoffsets = TopologicalSort(depedges); 398 | 399 | std::cout << "@@@ topological order start @@@" << std::endl; 400 | for(auto methodoffset : sorted_methodoffsets){ 401 | auto res = FindKeyByValue(methodname2offset, methodoffset); 402 | std::cout << "offset: " << methodoffset << " , name: " << *res << std::endl; 403 | } 404 | std::cout << "@@@ topological order end @@@" << std::endl; 405 | 406 | std::map patchvarspace; 407 | 408 | for(const auto & methodoffset : sorted_methodoffsets ){ 409 | panda_file::MethodDataAccessor mda(*pfile, panda_file::File::EntityId(methodoffset)); 410 | 411 | uint32_t cur_method = mda.GetMethodId().GetOffset(); 412 | if(skipfailfuns.find(cur_method) != skipfailfuns.end()){ 413 | continue; 414 | } 415 | 416 | result = DecompileFunction(prog, parser_program, ir_interface, mda, is_dynamic, &method2lexicalenvstack, &method2sendablelexicalenvstack, &patchvarspace, index2importnamespaces, localnamespaces, &class2memberfuns, &method2scriptfunast, &ctor2classdeclast, &memberfuncs, &class2father, &method2lexicalmap, &globallexical_waitlist, &globalsendablelexical_waitlist, &raw2newname, &methodname2offset); 417 | 418 | if(!result){ 419 | HandleError("#DecompilePandaFile: decomiple case 1 failed!"); 420 | } 421 | } 422 | 423 | 424 | cda.EnumerateMethods([prog, parser_program, ir_interface, is_dynamic, &result, &method2lexicalenvstack, &method2sendablelexicalenvstack, &patchvarspace, &index2importnamespaces, &localnamespaces, &class2memberfuns, &method2scriptfunast, &ctor2classdeclast, &memberfuncs, &class2father, &method2lexicalmap, &globallexical_waitlist, &globalsendablelexical_waitlist, &raw2newname, &methodname2offset, sorted_methodoffsets, &skipfailfuns](panda_file::MethodDataAccessor &mda){ 425 | if (!mda.IsExternal() && std::find(sorted_methodoffsets.begin(), sorted_methodoffsets.end(), mda.GetMethodId().GetOffset()) == sorted_methodoffsets.end() ){ 426 | uint32_t cur_method = mda.GetMethodId().GetOffset(); 427 | if(skipfailfuns.find(cur_method) != skipfailfuns.end()){ 428 | 429 | return; 430 | } 431 | 432 | result = DecompileFunction(prog, parser_program, ir_interface, mda, is_dynamic, &method2lexicalenvstack, &method2sendablelexicalenvstack, &patchvarspace, index2importnamespaces, localnamespaces, &class2memberfuns, &method2scriptfunast, &ctor2classdeclast, &memberfuncs, &class2father, &method2lexicalmap, &globallexical_waitlist, &globalsendablelexical_waitlist, &raw2newname, &methodname2offset); 433 | if(!result){ 434 | HandleError("#DecompilePandaFile: decomiple case 2 failed!"); 435 | } 436 | } 437 | }); 438 | } 439 | 440 | std::cout << "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" << std::endl; 441 | 442 | ConstructClasses(class2memberfuns, parser_program, ir_interface, class2father, method2scriptfunast, ctor2classdeclast, raw2newname); 443 | 444 | std::cout << "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" << std::endl; 445 | 446 | for (auto it = method2scriptfunast.begin(); it != method2scriptfunast.end(); ++it) { 447 | auto funcDecl = AllocNode(parser_program, it->second); 448 | 449 | program_ast->AddStatementAtPos(program_ast->Statements().size(), funcDecl); 450 | std::cout << "size:::: "<< program_statements.size() << std::endl; 451 | 452 | //std::cout << it->first << " MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; 453 | //LogAst(parser_program, outputAstFileName); 454 | } 455 | 456 | for (auto it = ctor2classdeclast.begin(); it != ctor2classdeclast.end(); ++it) { 457 | program_ast->AddStatementAtPos(program_ast->Statements().size(), it->second); 458 | 459 | //std::cout << it->first << " MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; 460 | //LogAst(parser_program, outputAstFileName); 461 | } 462 | 463 | LogAst(parser_program, outputAstFileName); 464 | LogArkTS2File(parser_program, outputFileName); 465 | 466 | std::cout << "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" << std::endl; 467 | 468 | return result; 469 | } 470 | 471 | void ConstructPandaFile2PandaAsmMaps(panda::disasm::Disassembler& disas, pandasm::AsmEmitter::PandaFileToPandaAsmMaps* maps){ 472 | for (const auto &[offset, name_value] : disas.string_offset_to_name_) { 473 | maps->strings[offset.GetOffset()] = std::string(name_value); 474 | } 475 | 476 | for (const auto &[name_value, offset] : disas.method_name_to_id_) { 477 | maps->methods[offset.GetOffset()] = std::string(name_value); 478 | } 479 | 480 | for (const auto &[name_value, offset] : disas.record_name_to_id_) { 481 | maps->classes[offset.GetOffset()] = std::string(name_value); 482 | } 483 | 484 | 485 | } 486 | 487 | bool DecompileBytecode(const std::string &pandafile_name, panda::disasm::Disassembler& disasm, 488 | bool is_dynamic, bool has_memory_pool) 489 | { 490 | 491 | if (!has_memory_pool) { 492 | PoolManager::Initialize(PoolType::MALLOC); 493 | } 494 | 495 | panda::pandasm::Program* prog = &disasm.prog_; 496 | pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps; 497 | 498 | ConstructPandaFile2PandaAsmMaps(disasm, &maps); 499 | 500 | auto ir_interface = BytecodeOptIrInterface(&maps, prog); 501 | 502 | auto res = DecompilePandaFile(prog, &ir_interface, pandafile_name, disasm, is_dynamic); 503 | 504 | if (!has_memory_pool) { 505 | PoolManager::Finalize(); 506 | } 507 | 508 | return res; 509 | } 510 | 511 | 512 | int main(int argc, char* argv[]) { 513 | if (argc > 1) { 514 | inputFileName = argv[1]; 515 | } 516 | if (argc > 2) { 517 | outputFileName = argv[2]; 518 | } 519 | 520 | panda::disasm::Disassembler disasm {}; 521 | disasm.Disassemble(inputFileName, false, false); 522 | disasm.CollectInfo(); 523 | 524 | DecompileBytecode(inputFileName, disasm, true, false); 525 | 526 | return 0; 527 | } 528 | --------------------------------------------------------------------------------