• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用 code cache 加速编译
2
3## code cache 简介
4
5JSVM 提供了生成并使用 code cache 加速编译过程的方法,其获取和使用分为下面几个部分:
6
7- 首先使用 compile 系列接口编译得到 JSVM_Script
8- 使用 OH_JSVM_CreateCodeCache 接口,传入编译完成后生成的 JSVM_Script
9- 将 OH_JSVM_CreateCodeCache 生成的 code cache 保存,等待下一次编译时,作为参数传递给 compile 系列接口
10
11通过上述流程,将会在使用 code cache 的那次编译中,极大减少编译时间,其原理为将编译完成的 script 序列化,然后使用 code cache 编译时就不再需要重新解析/编译已经被序列化的函数,只需要进行一次反序列化即可,编译就简化为了一次数据读取。
12
13## code cache 校验规格说明
14| 规格       | 规格说明                                            |
15| ---------- | -------------------------------------------------- |
16| 完整性校验  | 校验 cache 实际长度,是否与生成时一致                 |
17| 兼容性校验  | 校验生成 cache 的 JSVM 版本与编译选项是否与当前一致    |
18| 一致性校验  | 校验生成 cache 的 js 源码,是否与当前输入源码长度一致  |
19
20## 场景示例
21
22下面的伪代码是一个典型的使用方法,其中第二次编译,如果 cacheRejected 为 true,那么说明 code cache 被拒绝无法生效,运行时间会与无 code cache 时间一致;为 false 则这次运行将会极大加快。
23
24其中使用到的 JSVM-API 可以参考 [JSVM 数据类型与接口说明](./jsvm-data-types-interfaces.md),这里仅展示调用的步骤。
25外层跨语言交互的部分可以参考 [使用 JSVM-API 实现 JS 与 C/C++ 语言交互开发流程](./use-jsvm-process.md)。
26
27```c++
28#include "napi/native_api.h"
29#include "ark_runtime/jsvm.h"
30#include <hilog/log.h>
31
32JSVM_Value UseCodeCache(JSVM_Env env, JSVM_CallbackInfo info) {
33    // 编译参数准备
34    JSVM_Value jsSrc;
35    JSVM_Script script;
36    JSVM_Value result;
37    size_t length = 0;
38    const uint8_t* dataPtr = nullptr;
39    bool cacheRejected = true;
40    static std::string src = R"JS(
41        a = 65536;
42        b = 32768;
43        c = a + b;
44    )JS";
45
46    // 生成 code cache
47    {
48        JSVM_HandleScope handleScope;
49        OH_JSVM_OpenHandleScope(env, &handleScope);
50
51        // 源码字符串转换为 js 字符串
52        OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);
53
54        // 编译js代码
55        OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script);
56
57        // 执行js代码
58        OH_JSVM_RunScript(env, script, &result);
59        int value = 0;
60        OH_JSVM_GetValueInt32(env, result, &value);
61        OH_LOG_INFO(LOG_APP, "first run result: %{public}d\n", value);
62
63        if (dataPtr == nullptr) {
64            // 将js源码编译出的脚本保存到 cache, 可以避免重复编译, 带来性能提升
65            OH_JSVM_CreateCodeCache(env, script, &dataPtr, &length);
66        }
67
68        OH_JSVM_CloseHandleScope(env, handleScope);
69    }
70
71    // 使用 code cache
72    {
73        JSVM_HandleScope handleScope;
74        OH_JSVM_OpenHandleScope(env, &handleScope);
75
76        // 源码字符串转换为 js 字符串
77        OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);
78
79        // 使用 code cache 编译js代码
80        OH_JSVM_CompileScript(env, jsSrc, dataPtr, length, true, &cacheRejected, &script);
81
82        // 执行js代码
83        OH_JSVM_RunScript(env, script, &result);
84        int value = 0;
85        OH_JSVM_GetValueInt32(env, result, &value);
86        OH_LOG_INFO(LOG_APP, "second run result: %{public}d\n", value);
87
88        OH_JSVM_CloseHandleScope(env, handleScope);
89    }
90    OH_LOG_INFO(LOG_APP, "cache rejected: %{public}d\n", cacheRejected);
91    return result;
92}
93
94// Register a callback.
95static JSVM_CallbackStruct param[] = {
96    {.data = nullptr, .callback = UseCodeCache}
97};
98static JSVM_CallbackStruct *method = param;
99// Register the C++ callback as a JSVM globalThis.UseCodeCache property for the JS to call.
100static JSVM_PropertyDescriptor descriptor[] = {
101    {"UseCodeCache", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
102};
103```
104
105预期输出结果
106```
107first run result: 98304
108second run result: 98304
109cache rejected: 0
110```
111
112## 注意事项
113
114上述代码中使用了 code cache 进行编译: `OH_JSVM_CompileScript(env, jsSrc, dataPtr, length, true, &cacheRejected, &script);`
115这个接口的传入参数中包含 cacheRejected,用于接收实际编译过程中 code cache 是否被拒绝的状态,具体包括多种情况:
116
117- code cache 校验失败
118- code cache 校验成功
119- 内存中存在编译缓存,code cache 没有被校验
120
121对于第一种情况,这个参数会被置为 true,而后两种情况都是 false,因此需要注意即使 reject 为 false,也不能说明 code cache 被接收了。
122