1# JSVM-API Debugging
2
3JavaScript virtual machine (JSVM) is a standard JavaScript (JS) code execution engine that strictly complies with the ECMAScript specification. For details, see [JSVM](../reference/common/_j_s_v_m.md).
4
5The JSVM-based code debugging and tuning capabilities include Debugger, CPU Profiler, Heap Snapshot and Heap Statistics. The following APIs are involved:
6
7| API |  Description|
8|---|---|
9| OH_JSVM_GetVM  |  Obtains a VM instance.|
10| OH_JSVM_GetHeapStatistics  |  Obtains heap statistics of a VM.|
11| OH_JSVM_StartCpuProfiler  |  Creates and starts a CPU profiler instance.|
12| OH_JSVM_StopCpuProfiler  |  Stops the CPU profiler and outputs the result to a stream.|
13| OH_JSVM_TakeHeapSnapshot  |  Obtains a snapshot of the current heap and outputs it to a stream.|
14| OH_JSVM_OpenInspector  |  Opens an inspector instance on the specified host and port for debugging JS code.|
15| OH_JSVM_OpenInspectorWithName | Opens an inspector instance based on the PID and name. |
16| OH_JSVM_CloseInspector  |  Closes all remaining inspector connections.|
17| OH_JSVM_WaitForDebugger  |  Waits for the host to set up a socket connection with an inspector. After the connection is set up, the application continues to run. You can use **Runtime.runIfWaitingForDebugger** to run paused targets.|
18
19
20This topic describes how to use Debugger, CPU Profiler, and Heap Snapshot.
21
22## Using Debugger
23
24### Using OH_JSVM_OpenInspector
25
261. Configure the permission for accessing the Internet in the **module.json** file of the application project.
27
28   ```
29   "requestPermissions": [{
30     "name": "ohos.permission.INTERNET",
31     "reason": "$string:app_name",
32     "usedScene": {
33       "abilities": [
34         "FromAbility"
35       ],
36       "when": "inuse"
37     }
38   }]
39   ```
40
412. To prevent the pause during the debugging process from being falsely reported as no response, [enable the DevEco Studio debug mode](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-debug-arkts-debug-0000001767796366-V5) without setting breakpoints or run JSVM-API in threads except the main thread.
423. Call **OH_JSVM_OpenInspector** to open an inspector instance on the specified host and port. For example, call **OH_JSVM_OpenInspector(env, "localhost", 9225)** to create a socket on local port 9225 of the device.
434. Call **OH_JSVM_WaitForDebugger** to wait for the setup of a socket connection.
445. Check whether the port on the device is enabled successfully. For example, run **hdc shell "netstat -anp | grep 9225"**. If the status of port 9225 is **LISTEN**, the port is enabled.
456. Forward port. For example, run **hdc fport tcp:9229 tcp:9225** to forward PC port 9229 to device port 9225. If the command output is **Forwardport result:OK**, the port is forwarded successfully.
467. Enter **localhost:9229/json** in the address box of the Chrome browser and press **Enter**. Obtain port connection information. Copy the URL in the **devtoolsFrontendUrl** field to the address box and press **Enter**. <br>On the DevTools source code page displayed, the JS source code executed by **OH_JSVM_RunScript** in the application is displayed. The Debugger pauses at the first line of the JS source code.
478. You can set breakpoints on the source code page, send debugging commands using the buttons to control JS code execution, and view variables.
489. Call **OH_JSVM_CloseInspector** to close the inspector instance and release the socket connection.
49
50#### Example
51
52```cpp
53#include "ark_runtime/jsvm.h"
54
55#include <string>
56
57using namespace std;
58
59// JS source code to be debugged.
60static string srcDebugger = R"JS(
61const concat = (...args) => args.reduce((a, b) => a + b);
62var dialogue = concat('"What ', 'is ', 'your ', 'name ', '?"');
63dialogue = concat(dialogue, ' --', '"My ', 'name ', 'is ', 'Bob ', '."');
64)JS";
65
66// Enable the debugger.
67static void EnableInspector(JSVM_Env env) {
68    // Open an inspector instance on the specified host and port to create a socket.
69    OH_JSVM_OpenInspector(env, "localhost", 9225);
70    // Wait for the host to set up a socket connection with the inspector.
71    OH_JSVM_WaitForDebugger(env, true);
72}
73
74// Close the Debugger.
75static void CloseInspector(JSVM_Env env) {
76    // Close the inspector to release the socket connection.
77    OH_JSVM_CloseInspector(env);
78}
79
80static void RunScript(JSVM_Env env) {
81    JSVM_HandleScope handleScope;
82    OH_JSVM_OpenHandleScope(env, &handleScope);
83
84    JSVM_Value jsSrc;
85    OH_JSVM_CreateStringUtf8(env, srcDebugger.c_str(), srcDebugger.size(), &jsSrc);
86
87    JSVM_Script script;
88    OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script);
89
90    JSVM_Value result;
91    OH_JSVM_RunScript(env, script, &result);
92
93    OH_JSVM_CloseHandleScope(env, handleScope);
94}
95
96void RunDemo() {
97    JSVM_InitOptions initOptions{};
98    OH_JSVM_Init(&initOptions);
99
100    JSVM_VM vm;
101    OH_JSVM_CreateVM(nullptr, &vm);
102    JSVM_VMScope vmScope;
103    OH_JSVM_OpenVMScope(vm, &vmScope);
104
105    JSVM_Env env;
106    OH_JSVM_CreateEnv(vm, 0, nullptr, &env);
107    // Enable the Debugger before executing the JS code.
108    EnableInspector(env);
109    JSVM_EnvScope envScope;
110    OH_JSVM_OpenEnvScope(env, &envScope);
111
112    // Execute the JS code.
113    RunScript(env);
114
115    OH_JSVM_CloseEnvScope(env, envScope);
116    // Close the Debugger after the JS code is executed.
117    CloseInspector(env);
118    OH_JSVM_DestroyEnv(env);
119    OH_JSVM_CloseVMScope(vm, vmScope);
120    OH_JSVM_DestroyVM(vm);
121}
122```
123
124### Using OH_JSVM_OpenInspectorWithName
125
1261. Configure the permission for accessing the Internet in the **module.json** file of the application project.
127
128   ```
129   "requestPermissions": [{
130     "name": "ohos.permission.INTERNET",
131     "reason": "$string:app_name",
132     "usedScene": {
133       "abilities": [
134         "FromAbility"
135       ],
136       "when": "inuse"
137     }
138   }]
139   ```
140
1412. To prevent the pause during the debugging process from being falsely reported as no response, [enable the DevEco Studio debug mode](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-debug-arkts-debug-0000001767796366-V5) without setting breakpoints or run JSVM-API in threads except the main thread.
142
1433. Enable the inspector port and connect to devtools for debugging.<br>Before executing the JS code, call **OH_JSVM_OpenInspector** to open an inspector instance on the specified host and port and create a socket. For example, call **OH_JSVM_OpenInspectorWithName (env, 123, "test")** to create a TCP socket and the corresponding unixdomain port.
144
1454. Call **OH_JSVM_WaitForDebugger** to wait for the setup of a socket connection.
146
1475. Check whether the port on the device is enabled successfully. <br>Run **hdc shell "cat /proc/net/unix | grep jsvm"**. 
148
149   The Unix port is displayed, for example, **jsvm_devtools_remote_9229_123**, where **9229** is the TCP port number and **123** is the PID.
150
1516. Forward port. <br>Run **hdc fport tcp:9229 tcp:9229**. In this example, PC port 9229 is forwarded to device port 9229.<br>
152
153   If the command output is **Forwardport result:OK**, the port is forwarded successfully.
154
1557. Enter **localhost:9229/json** in the address box of the Google Chrome browser and press **Enter**. Obtain port connection information. Open the Chrome developer tool, copy the URL in the **devtoolsFrontendUrl** field to the address box, and press **Enter**. <br>On the DevTools source code page displayed, the JS source code executed by **OH_JSVM_RunScript** is displayed. The Debugger pauses at the first line of the JS source code.
156
1578. You can set breakpoints on the source code page, send debugging commands using the buttons to control JS code execution, and view variables.
158
1599. Call **OH_JSVM_CloseInspector** to close the inspector instance and release the socket connection.
160
161#### Example
162
163Replace the "//Enable the debugger" section with the following:
164```cpp
165// Enable the debugger.
166static void EnableInspector(JSVM_Env env) {
167    // Open an inspector instance on the specified host and port to create a socket.
168    OH_JSVM_OpenInspectorWithName(env, 123, "test");
169    // Wait for the host to set up a socket connection with the inspector.
170    OH_JSVM_WaitForDebugger(env, true);
171}
172```
173
174## Using CPU Profiler and Heap Snapshot
175
176### Using CPU Profiler APIs
177
1781. Before executing the JS code, call **OH_JSVM_StartCpuProfiler** to start sampling and return a **JSVM_CpuProfiler** instance.
1792. Run the JS code and call **OH_JSVM_StopCpuProfiler**, in which you need to pass in the **JSVM_CpuProfiler** instance (obtained in step 1), callback for the output stream, and pointer to the output stream. Then, the profiling data will be written to the specified output stream.
1803. Obtain the output data in JSON strings. You can also save it to the **.cpuprofile** file, which can be parsed into profiling views with the Chrome DevTools-JavaScript Profiler.
181
182### Using Heap Snapshot APIs
183
1841. To analyze the heap object creation of a piece of JS code, call **OH_JSVM_TakeHeapSnapshot** before and after the JS code is executed. You need to pass in the callback used to return the output stream and the pointer to the output stream. Then, the data will be written to the specified output stream.
1852. Save the output data to the **.heapsnapshot** file, which can be parsed into memory analysis views with the Chrome DevTools-Memory.
186
187### Example
188
189```cpp
190#include "ark_runtime/jsvm.h"
191
192#include <fstream>
193#include <iostream>
194
195using namespace std;
196
197// JS code to be optimized.
198static string srcProf = R"JS(
199function sleep(delay) {
200    var start = (new Date()).getTime();
201    while ((new Date()).getTime() - start < delay) {
202        continue;
203    }
204}
205
206function work3() {
207    sleep(300);
208}
209
210function work2() {
211    work3();
212    sleep(200);
213}
214
215function work1() {
216    work2();
217    sleep(100);
218}
219
220work1();
221)JS";
222
223// Callback for the data output stream, which is customized to process the returned data. In this example, the output data is written to a file.
224static bool OutputStream(const char *data, int size, void *streamData) {
225    auto &os = *reinterpret_cast<ofstream *>(streamData);
226    if (data) {
227        os.write(data, size);
228    } else {
229        os.close();
230    }
231    return true;
232}
233
234static JSVM_CpuProfiler ProfilingBegin(JSVM_VM vm) {
235    // Specify the path of the file saving the output profiling data. In this example, the sandbox path is /data/storage/el2/base/files, and the bundle name is com.example.helloworld.
236    // The output data will be saved to /data/app/el2/100/base/com.example.helloworld/files/heap-snapshot-begin.heapsnapshot.
237    ofstream heapSnapshot("/data/storage/el2/base/files/heap-snapshot-begin.heapsnapshot",
238                          ios::out | ios:: binary | ios::trunc);
239    // Task a heap snapshot before the JS code is executed.
240    OH_JSVM_TakeHeapSnapshot(vm, OutputStream, &heapSnapshot);
241    JSVM_CpuProfiler cpuProfiler;
242    // Start the CPU Profiler.
243    OH_JSVM_StartCpuProfiler(vm, &cpuProfiler);
244    return cpuProfiler;
245}
246
247// Stop the profiling data collection tool.
248static void ProfilingEnd(JSVM_VM vm, JSVM_CpuProfiler cpuProfiler) {
249    // Specify the path of the file saving the output profiling data. In this example, the sandbox path is /data/storage/el2/base/files, and the bundle name is com.example.helloworld.
250    // The output data will be saved to /data/app/el2/100/base/com.example.helloworld/files/cpu-profile.cpuprofile.
251    ofstream cpuProfile("/data/storage/el2/base/files/cpu-profile.cpuprofile",
252                        ios::out | ios:: binary | ios::trunc);
253    // Stop the CPU Profiler to obtain data.
254    OH_JSVM_StopCpuProfiler(vm, cpuProfiler, OutputStream, &cpuProfile);
255    ofstream heapSnapshot("/data/storage/el2/base/files/heap-snapshot-end.heapsnapshot",
256                              ios::out | ios:: binary | ios::trunc);
257    // After the JS is executed, take a heap snapshot again and compare the two snapshots for further analysis.
258    OH_JSVM_TakeHeapSnapshot(vm, OutputStream, &heapSnapshot);
259}
260
261static void RunScriptWithStatistics(JSVM_Env env) {
262    JSVM_VM vm;
263    OH_JSVM_GetVM(env, &vm);
264
265    // Start profiling.
266    auto cpuProfiler = ProfilingBegin(vm);
267
268    JSVM_HandleScope handleScope;
269    OH_JSVM_OpenHandleScope(env, &handleScope);
270
271    JSVM_Value jsSrc;
272    OH_JSVM_CreateStringUtf8(env, srcProf.c_str(), srcProf.size(), &jsSrc);
273
274    JSVM_Script script;
275    OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script);
276
277    JSVM_Value result;
278    // Execute the JS code.
279    OH_JSVM_RunScript(env, script, &result);
280
281    OH_JSVM_CloseHandleScope(env, handleScope);
282
283    // End profiling.
284    ProfilingEnd(vm, cpuProfiler);
285}
286
287void RunDemo() {
288    JSVM_InitOptions initOptions{};
289    OH_JSVM_Init(&initOptions);
290
291    JSVM_VM vm;
292    OH_JSVM_CreateVM(nullptr, &vm);
293    JSVM_VMScope vmScope;
294    OH_JSVM_OpenVMScope(vm, &vmScope);
295
296    JSVM_Env env;
297    OH_JSVM_CreateEnv(vm, 0, nullptr, &env);
298    JSVM_EnvScope envScope;
299    OH_JSVM_OpenEnvScope(env, &envScope);
300
301    RunScriptWithStatistics(env);
302
303    OH_JSVM_CloseEnvScope(env, envScope);
304    OH_JSVM_DestroyEnv(env);
305    OH_JSVM_CloseVMScope(vm, vmScope);
306    OH_JSVM_DestroyVM(vm);
307}
308```
309<!--no_check-->