• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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