# 方舟运行时使用指南 ## 方舟编译器简介 方舟编译器(ArkCompiler)是为支持多种编程语言、多种芯片平台的联合编译、运行而设计的统一编译运行时平台。 * ArkCompiler主要分成两个部分:编译工具链与运行时。 * ArkCompiler eTS Runtime主要由四个子系统组成:Core Subsystem、Execution Subsystem、Compiler Subsystem、Runtime subsystem。 * ArkCompiler 的设计特点:原生支持类型、并发模型优化与并发API、安全。 要了解虚拟机的详细设计请参考 [概述](overview-zh.md) ## 环境搭建和编译 ### 环境配置 #### 搭建Ubuntu环境 - 初始环境软件安装(Ubuntu版本推荐18.04或20.04) ``` sudo apt-get update sudo apt-get upgrade sudo apt-get install git-lfs git bison flex gnupg build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses-dev x11proto-core-dev libx11-dev libc++1 lib32z1-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip m4 libtinfo5 bc npm genext2fs liblz4-tool libssl-dev ruby openjdk-8-jre-headless gdb python3-pip libelf-dev libxcursor-dev libxrandr-dev libxinerama-dev ``` 详细Ubuntu安装搭建请参考 [搭建Ubuntu环境](https://developer.huawei.com/consumer/cn/training/course/video/C101639988048536240) #### 源码获取 下载源码请参考 [下载说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md) ### 代码编译 注意:下列命令需在源码根目录下执行 1. 首次编译: ``` ./build.sh --product-name rk3568 ``` 2. 首次编译后增量编译方舟运行时: 编译linux-x86版本: ``` ./build.sh --product-name rk3568 --build-target ark_js_host_linux_tools_packages ``` 编译oh-arm64版本: ``` ./build.sh --product-name rk3568 --gn-args use_musl=true --target-cpu arm64 --build-target ark_js_packages ``` 编译oh-arm32版本: ``` ./build.sh --product-name rk3568 --build-target ark_js_packages ``` 3. 首次编译后增量编译方舟前端: ``` ./build.sh --product-name rk3568 --build-target ets_frontend_build ``` 更多编译命令请参考 [编译命令](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-arkcompiler-guide.md) **说明**:上述编译命令为release版本,编译debug版本需增加编译选项:--gn-args is_debug=true。 方舟相关的二进制文件在如下路径: ``` out/rk3568/arkcompiler/runtime_core/ out/rk3568/arkcompiler/ets_frontend/ out/rk3568/arkcompiler/ets_runtime/ out/rk3568/clang_x64/arkcompiler/runtime_core/ out/rk3568/clang_x64/arkcompiler/ets_frontend/ out/rk3568/clang_x64/arkcompiler/ets_runtime ``` ## 开发实例 本章节将介绍基于方舟运行时的开发测试实例。 ### HelloWorld #### 运行前准备 * 编译编译方舟运行时和方舟前端 ``` ./build.sh --product-name rk3568 --build-target ark_js_host_linux_tools_packages --build-target ets_frontend_build ``` #### 运行hello-world.js 新建hello-world.js文件,写入以下源码: ``` print("Hello World!!!"); ``` 运行步骤: 1. 通过方舟前端生成hello-world.abc文件,编译命令: ``` node --expose-gc /your_code_path/out/rk3568/clang_x64/arkcompiler/ets_frontend/build/src/index.js hello-world.js ``` **注意**:使用node编译abc过程遇到ENOENT错误,运行如下命令进行修复 ``` npm cache clean --force cd /your_code_path/arkcompiler/ets_frontend/ts2panda npm install cd /your_code_path/out/rk3568/clang_x64/arkcompiler/ets_frontend/build npm install ``` 2. 执行hello-world.abc文件: 1. 设置搜索路径: ``` export LD_LIBRARY_PATH=/your_code_path/out/rk3568/clang_x64/arkcompiler/ets_runtime:/your_code_path/out/rk3568/clang_x64/global/i18n_standard:/your_code_path/prebuilts/clang/ohos/linux-x86_64/llvm/lib:/your_code_path/out/rk3568/clang_x64/thirdparty/zlib ``` 2. 执行ark\_js\_vm: ``` /your_code_path/out/rk3568/clang_x64/arkcompiler/ets_runtime/ark_js_vm hello-world.abc ``` 执行结果如下: ``` Hello World!!! ``` **说明**:此处“_your_code_path_”为源码目录路径。 #### 反汇编hello-world.abc 编译生成反汇编工具: ``` ./build.sh --product-name rk3568 --build-target ark_host_linux_tools_packages ``` 执行如下命令,结果输出到output.pa文件中: ``` /your_code_path/out/rk3568/clang_x64/arkcompiler/runtime_core/ark_disasm hello-world.abc output.pa ``` hello-world.abc反汇编结果如下: ``` # # source binary: hello-world.abc # # ==================== # LITERALS # ==================== # RECORDS .record _ESAnnotation .record _ESModuleMode { u8 isModule } # ==================== # METHODS .function any func_main_0_any_any_any_any_(any a0, any a1, any a2) { mov v2, a2 mov v1, a1 mov v0, a0 builtin.acc sta v5 builtin.idi "print", 0x0 // 加载print函数 sta v3 lda.str "Hello World!!!" // 加载Hello World!!!字符串 sta v4 builtin.tern3 v3, v4 // 调用print函数 builtin.acc } ``` ### 运行Test262测试用例 #### 运行前准备 1. 编译方舟运行时,编译命令: ``` ./build.sh --product-name rk3568 --build-target ark_js_host_linux_tools_packages ``` 2. 编译方舟前端,编译命令: ``` ./build.sh --product-name rk3568 --build-target ets_frontend_build ``` **说明**:编译命令执行路径为项目根目录。 #### 运行Test262 运行run\_test262.py脚本,下载及运行Test262用例。 命令行格式: ``` python3 test262/run_test262.py [options] ``` 执行路径为:项目根目录/arkcompiler/ets_frontend。

选项

描述

--h,--help

帮助提示

--dir DIR

选定要测试的目录

--file FILE

选定要测试的文件

--mode [{1, 2, 3}]

模式选择,1:仅默认值;2:仅严格模式;3:默认模式和严格模式

--es51

运行Test262 ES5.1版本

--es2015 [{all, only}]

运行Test262 ES2015版本,all:包含的所有用例;only:仅包括ES2015

--esnext

运行Test262-ES.next

--engine FILE

运行测试的其他引擎,指定二进制文件(如:d8,hermes,jsc,qjs...)

--babel

是否使用Babel转换

--timeout TIMEOUT

设置测试超时时间(以毫秒为单位)

--threads THREADS

设置并行运行线程数

--hostArgs HOSTARGS

传递给eshost主机的命令行参数

--ark-tool ARK_TOOL

方舟运行时的二进制工具

--ark-frontend-tool ARK_FRONTEND_TOOL

方舟前端转换工具

--libs-dir LIBS_DIR

依赖so的路径集合,通过“:”分割

--ark-frontend [{ts2panda, es2panda}]

指定前端

#### 测试运行示例 - 运行ES51测试用例: ``` python3 test262/run_test262.py --es51 ``` - 仅运行ES2015测试用例: ``` python3 test262/run_test262.py --es2015 ``` - 仅运行ES2021测试用例: ``` python3 test262/run_test262.py --es2021 only ``` - 运行ES2015和ES51和ES2021所有测试用例: ``` python3 test262/run_test262.py --es2021 all ``` - 运行单一测试用例: ``` python3 test262/run_test262.py --file test262/data/test_es5/language/statements/break/12.8-1.js ``` - 运行某目录下所有测试用例: ``` python3 test262/run_test262.py --dir test262/data/test_es5/language/statements ``` - 使用\`babel\`把单个测试用例转换成es5后再运行: ``` python3 test262/run_test262.py --babel --file test262/data/test_es5/language/statements/break/12.8-1.js ``` #### 测试输出 Test262所有用例的测试结果位于项目根目录/arkcompiler/ets_frontend/out下。shell中测试输出结果如下: ``` $python3 test262/run_test262.py --file test262/data/test_es2015/built-ins/Array/15.4.5.1-5-1.js Wait a moment.......... Test command: node test262/harness/bin/run.js --hostType=panda --hostPath=python3 --hostArgs='-B test262/run_sunspider.py --ark-tool=/your_code_path/out/rk3568/clang_x64/arkcompiler/ets_runtime/ark_js_vm --ark-frontend-tool=/your_code_path/out/rk3568/clang_x64/arkcompiler/ets_frontend/build/src/index.js --libs-dir=/your_code_path/out/rk3568/clang_x64/global/i18n:/your_code_path/prebuilts/clang/ohos/linux-x86_64/llvm/lib:/your_code_path/out/rk3568/clang_x64/thirdparty/zlib/ --ark-frontend=ts2panda' --threads=15 --mode=only strict mode --timeout=60000 --tempDir=build/test262 --test262Dir=test262/data --saveCompiledTests test262/data/test_es5/language/statements/break/12.8-1.js PASS test262/data/test_es2015/built-ins/Array/15.4.5.1-5-1.js (strict mode) Ran 1 tests 1 passed 0 failed used time is: 0:01:04.439642 ``` ### AOT执行 #### 运行前准备 * 编译生成AOT编译器: ``` ./build.sh --product-name rk3568 --build-target ets_frontend_build --build-target ark_js_host_linux_tools_packages --build-target ark_host_linux_tools_packages ``` #### 运行hello-world.ts 新建hello-world.ts文件,写入以下源码: ``` declare function print(arg:any):string; print('Hello World!!!') ``` 运行步骤: 1. 通过方舟前端生成hello-world.abc文件,编译命令: ``` node --expose-gc /your_code_path/out/rk3568/clang_x64/arkcompiler/ets_frontend/build/src/index.js -m --merge-abc test1/test.ts ``` 2. 执行hello-world.abc文件: 1. 设置搜索路径: ``` export LD_LIBRARY_PATH=/your_code_path/out/rk3568/clang_x64/arkcompiler/ets_runtime:/your_code_path/out/rk3568/clang_x64/global/i18n_standard:/your_code_path/prebuilts/clang/ohos/linux-x86_64/llvm/lib:/your_code_path/out/rk3568/clang_x64/thirdparty/icu:/your_code_path/out/rk3568/clang_x64/thirdparty/zlib ``` 2. 通过AOT编译器生成an和ai文件: ``` /your_code_path/out/rk3568/clang_x64/arkcompiler/ets_runtime/ark_aot_compiler --aot-file=./hello-world hello-world.abc ``` 3. 执行ark\_js\_vm: ``` /your_code_path/out/rk3568/clang_x64/arkcompiler/ets_runtime/ark_js_vm --aot-file=./hello-world --entry-point=hello-world hello-world.abc ``` 执行结果如下: ``` Hello World!!! ``` **说明**:此处“_your_code_path_”为源码目录路径。 ## 工具链使用 方舟前端工具采用命令行交互方式,支持将ArkTS代码转换为方舟字节码,使其能够在方舟运行时上运行。支持Windows/Linux/Mac平台。 ### ArkTS字节码编译工具概述 使用前端工具将ArkTS文件转换为方舟字节码文件。方舟前端工具在linux平台上可通过全量编译或指定编译前端工具链获取。 构建编译: ``` $ ./build.sh --product-name rk3568 --build-target ark_ts2abc_build ``` 安装 `node`和 `npm`后, 使用前端工具: ``` $ cd out/rk3568/clang_x64/arkcompiler/ets_frontend/build $ npm install $ node --expose-gc src/index.js [选项] file.js ```

选项

缩写

描述

取值范围

默认值

--modules

-m

按照Module方式编译

-

-

--debug-log

-l

使能log信息

-

-

--dump-assembly

-a

输出为可读文本格式的字节码文件

-

-

--debug

-d

携带debug信息

-

-

--show-statistics

-s

显示字节码相关的统计信息

-

-

--output

-o

输出文件路径

-

-

--timeout

-t

超时门限

-

-

--help

-h

帮助提示

-

-

--bc-version

-v

输出当前字节码版本

-

-

--bc-min-version

  

输出支持的最低字节码版本

-

-

### 反汇编器工具概述 工具名称为ark\_disasm,用于将二进制格式的方舟字节码文件转换为文本格式的方舟字节码文件。 编译生成反汇编工具: ``` ./build.sh --product-name rk3568 --build-target ark_host_linux_tools_packages ``` 命令行格式: ``` ark_disasm [选项] 输入文件 输出文件 ```

选项

描述

--debug

使能调试信息, 如果没有指定"--debug-file", 输出形式将会是标准输出。默认值是false

--debug-file

调试信息输出文件路径,默认为std::cout

--skip-string-literals

将字符串用对应的string_ID代替,可以减少输出文件的大小。默认值是false

--quiet

打开所有--skip-*选项。默认值是false

--help

帮助提示

--verbose

输出更多关于类和方法在文件中的信息。默认值是false

输入文件:二进制格式的方舟字节码 输出文件:文本格式的方舟字节码 ### AOT工具概述 AOT为Ahead Of Time的简称,也即提前编译,能够在Host端将字节码提前编译成Target端可运行的机器码,这样字节码可以获得充分编译优化,从而加速Target端的运行速度。 编译生成aot编译器: ``` ./build.sh --product-name rk3568 --build-target ark_js_host_linux_tools_packages ``` 命令行格式: ``` ark_aot_compiler [选项] 输入文件 ``` | 选项 | 描述 | | ----------------------- | ----------------------------------------------------------------------------------- | | --aot-file | AOT输出文件的路径(不需要文件后缀)。默认值:“aot_file” | | --compiler-opt-type-lowering | 利用类型信息,生成优化级别更高的机器码。默认值:“true” | | --compiler-opt-max-method | 设置AOT编译方法的大小阈值,当方法的大小超过该值时,则不进行编译。默认值:“32KB” | | --compiler-opt-level | 设置AOT的优化级别。默认值:“3” | | --compiler-log | AOT的日志选项,可打印出AOT生成的IR图、汇编码等信息。默认值“none” | | --compiler-log-snapshot | 打印与序列化有关的日志信息。默认值“false” | | --compiler-log-time | 打印AOT过程中各个优化pass的耗时情况。默认值值“false” | 输入文件:二进制格式的方舟字节码 输出文件:直接执行的机器码的an文件、存储序列化后ConstPool的ai文件(输出文件路径需使用--aot-file选项指定) ### PGO工具概述 PGO为Profile-guided optimization的简称,也即配置文件引导的优化。该工具能够记录应用启动和性能场景中的高频(热点)函数,并将信息记录于对应的PGO Profiler文件。AOT编译器则可通过这些信息决策部分函数进行编译,从而在基本不影响应用运行性能的情况下,缩短编译时间,减少.an文件的大小。 编译生成aot编译器和ark js虚拟机 ``` ./build.sh --product-name rk3568 --build-target ark_js_host_linux_tools_packages ``` ### 生成PGO Profiler文件 命令行格式: ``` ark_js_vm [选项] 输入文件 ``` | 选项 | 描述 | | ----------------------- | ----------------------------------------------------------------------------------- | | --enable-pgo-profiler | 开启pgo工具。默认值:“false” | | --pgo-profiler-path | pgo profiler文件的保存路径。默认值:当前路径 | | --pgo-hotness-threshold | 热点函数的阈值,当函数的调用次数大于该值,则认为是热点函数。默认值:“2” | 输入文件:二进制格式的方舟字节码 输出文件:保存有热点函数信息的ap文件 ### 基于PGO Profiler的AOT编译 命令行格式: ``` ark_aot_compiler [选项] 输入文件 ``` | 选项 | 描述 | | ----------------------- | ----------------------------------------------------------------------------------- | | --pgo-profiler-path | pgo profiler文件路径。默认值:“none” | | --pgo-hotness-threshold | 使能pgo编译的函数调用次数阈值,profile文件中记录的调用次数大于该阈值的函数才会进行编译。默认值:“2”| 输入文件:二进制格式的方舟字节码,ap文件 输出文件:直接执行的机器码的an文件(基于pgo)