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