1# Working with VM Snapshots Using JSVM-API 2 3## Introduction 4 5A JavaScript virtual machine (JSVM) snapshot records the state of a JSVM at a particular time point. The snapshot file contains information, such as the current heap memory, execution context, and function closure. 6 7## Basic Concepts 8 9- VM startup snapshot: a snapshot of the VM status at a specific time, including all internal status and data of the VM. The snapshot can be used to quickly restore the VM to the state it was when the snapshot was created. 10 11It helps simplify complex programming tasks and shorten the creation time of a JS context, making the application more efficient and stable. 12 13## Available APIs 14 15| API | Description | 16|----------------------------|-------------------------------| 17| OH_JSVM_CreateSnapshot | Creates a VM startup snapshot. | 18|OH_JSVM_CreateEnvFromSnapshot| Creates an environment based on the start snapshot of a VM.| 19## Example 20 21If you are just starting out with JSVM-API, see [JSVM-API Development Process](use-jsvm-process.md). The following demonstrates only the C++ and ArkTS code related to the snapshot-related APIs. 22 23### OH_JSVM_CreateSnapshot 24 25Use **OH_JSVM_CreateSnapshot** to create a VM startup snapshot. 26 27CPP code: 28 29```cpp 30// hello.cpp 31#include "napi/native_api.h" 32#include "ark_runtime/jsvm.h" 33#include <hilog/log.h> 34#include <fstream> 35 36// Register the CreateAndUseSnapshot callback. 37static JSVM_CallbackStruct param[] = { 38 {.data = nullptr, .callback = CreateAndUseSnapshot}, 39}; 40static JSVM_CallbackStruct *method = param; 41// Set a property descriptor named createAndUseSnapshot and associate it with a callback. This allows the CreateAndUseSnapshot callback to be called from JS. 42static JSVM_PropertyDescriptor descriptor[] = { 43 {"createAndUseSnapshot", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 44}; 45 46static const int MAX_BUFFER_SIZE = 128; 47// Allow the JSVM to call the CreateHelloString() function when needs, using the callback struct and external references. 48static JSVM_Value CreateHelloString(JSVM_Env env, JSVM_CallbackInfo info) 49{ 50 JSVM_Value outPut; 51 OH_JSVM_CreateStringUtf8(env, "Hello world!", JSVM_AUTO_LENGTH, &outPut); 52 return outPut; 53} 54// Enable the JSVM to call the bound function through external references. 55static JSVM_CallbackStruct helloCb = {CreateHelloString, nullptr}; 56// externals is an array of external references that include a pointer to helloCb. 57static intptr_t externals[] = { 58 (intptr_t)&helloCb, 59 0, 60}; 61 62static JSVM_Value RunVMScript(JSVM_Env env, std::string &src) 63{ 64 // Open the handle scope. 65 JSVM_HandleScope handleScope; 66 OH_JSVM_OpenHandleScope(env, &handleScope); 67 JSVM_Value jsStr = nullptr; 68 OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsStr); 69 // Compile the JS code. 70 JSVM_Script script; 71 OH_JSVM_CompileScript(env, jsStr, nullptr, 0, true, nullptr, &script); 72 // Execute the JS code. 73 JSVM_Value result = nullptr; 74 OH_JSVM_RunScript(env, script, &result); 75 // Close the handle scope. 76 OH_JSVM_CloseHandleScope(env, handleScope); 77 return result; 78} 79// Define OH_JSVM_CreateSnapshot. 80static void CreateVMSnapshot() { 81 // Create a JSVM instance and open the VM scope. 82 JSVM_VM vm; 83 JSVM_CreateVMOptions vmOptions; 84 memset(&vmOptions, 0, sizeof(vmOptions)); 85 // Use isForSnapshotting to set whether the VM is used for creating snapshots. 86 vmOptions.isForSnapshotting = true; 87 OH_JSVM_CreateVM(&vmOptions, &vm); 88 JSVM_VMScope vmScope; 89 OH_JSVM_OpenVMScope(vm, &vmScope); 90 // Create a JS environment and open the environment scope. 91 JSVM_Env env; 92 // Register the native function as a method that can be called from JS. 93 JSVM_PropertyDescriptor descriptor[] = { 94 {"createHelloString", nullptr, &helloCb, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 95 }; 96 OH_JSVM_CreateEnv(vm, 1, descriptor, &env); 97 JSVM_EnvScope envScope; 98 OH_JSVM_OpenEnvScope(env, &envScope); 99 // Use OH_JSVM_CreateSnapshot to create a VM startup snapshot. 100 const char *blobData = nullptr; 101 size_t blobSize = 0; 102 JSVM_Env envs[1] = {env}; 103 JSVM_Status status = OH_JSVM_CreateSnapshot(vm, 1, envs, &blobData, &blobSize); 104 if (status == JSVM_OK) { 105 OH_LOG_INFO(LOG_APP, "Test JSVM OH_JSVM_CreateSnapshot success, blobSize = : %{public}ld", blobSize); 106 } 107 // Save the snapshot to a file. 108 // Save the snapshot data to the /data/storage/el2/base/files/test_blob.bin directory, which is a sandbox directory. 109 // For example, the bundle name is com.example.jsvm. The snapshot file is saved in /data/app/el2/100/base/com.example.jsvm/files/test_blob.bin. 110 std::ofstream file("/data/storage/el2/base/files/test_blob.bin", 111 std::ios::out | std::ios::binary | std::ios::trunc); 112 file.write(blobData, blobSize); 113 file.close(); 114 // Close and destroy the environment and the VM. 115 OH_JSVM_CloseEnvScope(env, envScope); 116 OH_JSVM_DestroyEnv(env); 117 OH_JSVM_CloseVMScope(vm, vmScope); 118 OH_JSVM_DestroyVM(vm); 119} 120static void RunVMSnapshot() { 121 // The lifespan of blobData cannot be shorter than that of the VM. 122 // Read the snapshot from the file. 123 std::vector<char> blobData; 124 std::ifstream file("/data/storage/el2/base/files/test_blob.bin", std::ios::in | std::ios::binary | std::ios::ate); 125 size_t blobSize = file.tellg(); 126 blobData.resize(blobSize); 127 file.seekg(0, std::ios::beg); 128 file.read(blobData.data(), blobSize); 129 file.close(); 130 OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot read file blobSize = : %{public}ld", blobSize); 131 // Use the snapshot data to create a VM instance. 132 JSVM_VM vm; 133 JSVM_CreateVMOptions vmOptions; 134 memset(&vmOptions, 0, sizeof(vmOptions)); 135 vmOptions.snapshotBlobData = blobData.data(); 136 vmOptions.snapshotBlobSize = blobSize; 137 OH_JSVM_CreateVM(&vmOptions, &vm); 138 JSVM_VMScope vmScope; 139 OH_JSVM_OpenVMScope(vm, &vmScope); 140 // Create an environment from the snapshot. 141 JSVM_Env env; 142 OH_JSVM_CreateEnvFromSnapshot(vm, 0, &env); 143 JSVM_EnvScope envScope; 144 OH_JSVM_OpenEnvScope(env, &envScope); 145 // Execute the JS script. createHelloString() is defined in env of the snapshot record. 146 std::string src = "createHelloString()"; 147 JSVM_Value result = RunVMScript(env, src); 148 // Check the script execution result before closing the environment. 149 if (result == nullptr) { 150 OH_JSVM_ThrowError(env, nullptr, "Test JSVM RunVMSnapshot-RunVMScript result is nullptr"); 151 return; 152 } 153 char str[MAX_BUFFER_SIZE]; 154 OH_JSVM_GetValueStringUtf8(env, result, str, MAX_BUFFER_SIZE, nullptr); 155 OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot-RunVMScript result is: %{public}s", str); 156 // Close and destroy the environment and the VM. 157 OH_JSVM_CloseEnvScope(env, envScope); 158 OH_JSVM_DestroyEnv(env); 159 OH_JSVM_CloseVMScope(vm, vmScope); 160 OH_JSVM_DestroyVM(vm); 161 return; 162} 163 164static JSVM_Value CreateAndUseSnapshot(JSVM_Env env, JSVM_CallbackInfo info) 165{ 166 // Initialize OH_JSVM_Init(&initOptions) in the first initialization of RunJsVm() in the development process. The initialization can be performed only once. 167 // The value assignment of initOptions is completed in the development process. 168 // Create a VM snapshot and save it to a file. 169 CreateVMSnapshot(); 170 // The snapshot records the specific JS execution environment and can be used to quickly restore the JS execution context environment across processes. 171 RunVMSnapshot(); 172 JSVM_Value result = nullptr; 173 OH_JSVM_CreateInt32(env, 0, &result); 174 return result; 175} 176``` 177 178ArkTS code: 179 180```ts 181import hilog from "@ohos.hilog" 182// Import the native APIs. 183import napitest from "libentry.so" 184let script: string = ` 185 createAndUseSnapshot() 186` 187try { 188 let result = napitest.runJsVm(script); 189 hilog.info(0x0000, 'testJSVM', 'Test JSVM createAndUseSnapshot: %{public}s', result); 190} catch (error) { 191 hilog.error(0x0000, 'testJSVM', 'Test JSVM createAndUseSnapshot error: %{public}s', error.message); 192} 193``` 194