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