1e41f4b71Sopenharmony_ci# Performing Lifecycle Management Using JSVM-API 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## Introduction 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ciIn JSVM-API, **JSVM_Value** is an abstract data type that represents a JavaScript (JS) value of any type, which includes the basic type (such as number, string, or Boolean) and the composite type (such as array, function, or object). 6e41f4b71Sopenharmony_ciThe **JSVM_Value** lifecycle is closely related to the lifecycle of the JS value. When a JS value is garbage-collected, the **JSVM_Value** associated with it is no longer valid. Avoid using the **JSVM_Value** when the JS value no longer exists. 7e41f4b71Sopenharmony_ci 8e41f4b71Sopenharmony_ciScope is used to manage the **JSVM_Value** lifecycle in the framework layer. You can use **OH_JSVM_OpenHandleScope** to create a scope and use **OH_JSVM_CloseHandleScope** to destroy a scope. By creating a **JSVM_Value** in a scope, you can ensure that the **JSVM_Value** is automatically released when the scope ends. This helps prevent memory leaks. 9e41f4b71Sopenharmony_ci 10e41f4b71Sopenharmony_ci**JSVM_Ref** is a JSVM-API data type used to manage the **JSVM_Value** lifecycle. It allows reference to a **JSVM_Value** during its lifecycle, even if the value is beyond its original context. The reference allows a **JSVM_Value** to be shared in different contexts and released in a timely manner. 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ciProperly using **OH_JSVM_OpenHandleScope** and **OH_JSVM_CloseHandleScope** can minimize the **JSVM_Value** lifecycle and prevent memory leaks. 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ciEach **JSVM_Value** belongs to a specific **HandleScope** instance, which is created by **OH_JSVM_OpenHandleScope** and closed by **OH_JSVM_CloseHandleScope**. After a **HandleScope** instance is closed, the corresponding **JSVM_Value** will be automatically released. 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci## Basic Concepts 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ciJSVM-API provides APIs for creating and manipulating JS objects, managing references to and lifecycle of the JS objects, and registering garbage collection (GC) callbacks in C/C++. Before you get started, you need to understand the following concepts: 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci- Scope: used to ensure that the objects created within a certain scope remain active and are properly cleared when no longer required. JSVM-API provides APIs for creating and closing normal and escapeable scopes. 21e41f4b71Sopenharmony_ci- Reference management: JSVM-API provides APIs for creating, deleting, and managing object references to extend the object lifecycle and prevent memory leaks when objects are used. 22e41f4b71Sopenharmony_ci- Escapeable scope: used to return the values created within the **escapable_handle_scope** to a parent scope. It is created by **OH_JSVM_OpenEscapableHandleScope** and closed by **OH_JSVM_CloseEscapableHandleScope**. 23e41f4b71Sopenharmony_ci- GC callback: You can register GC callbacks to perform specific cleanup operations when JS objects are garbage-collected. 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ciUnderstanding these concepts helps you securely and effectively manipulate JS objects in C/C++ and perform object lifecycle management. 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci## Available APIs 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci| API | Description | 30e41f4b71Sopenharmony_ci|----------------------------|--------------------------------| 31e41f4b71Sopenharmony_ci| OH_JSVM_OpenHandleScope | Opens a handle scope. **JSVM_Value** within the scope will not be garbage-collected.| 32e41f4b71Sopenharmony_ci| OH_JSVM_CloseHandleScope | Closes a handle scope.| 33e41f4b71Sopenharmony_ci| OH_JSVM_OpenEscapableHandleScope | Opens an escapable handle scope. Before this scope is closed, the object created within the scope has the same lifecycle as its parent scope.| 34e41f4b71Sopenharmony_ci| OH_JSVM_CloseEscapableHandleScope | Closes an escapable handle scope.| 35e41f4b71Sopenharmony_ci| OH_JSVM_EscapeHandle | Promotes a handle to a JS object so that it is valid for the lifetime of the outer scope.| 36e41f4b71Sopenharmony_ci| OH_JSVM_CreateReference | Creates a reference with the specified reference count to the value passed in. The reference allows objects to be used and shared in different contexts and helps effective track of the object lifecycle.| 37e41f4b71Sopenharmony_ci| OH_JSVM_DeleteReference | Releases the reference created by **OH_JSVM_CreateReference**. This allows objects to be correctly released and reclaimed when they are no longer required, avoiding memory leaks.| 38e41f4b71Sopenharmony_ci| OH_JSVM_ReferenceRef | Increments the reference count of the reference created by **OH_JSVM_CreateReference** so that the object referenced will not be released.| 39e41f4b71Sopenharmony_ci| OH_JSVM_ReferenceUnref | Decrements the reference count of the reference created by **OH_JSVM_CreateReference** so that the object can be correctly released and reclaimed when it is not referenced.| 40e41f4b71Sopenharmony_ci| OH_JSVM_GetReferenceValue | Obtains the object referenced by **OH_JSVM_CreateReference**. | 41e41f4b71Sopenharmony_ci| OH_JSVM_AddFinalizer | Adds a **JSVM_Finalize** callback to a JS object. The callback will be invoked to release the native object when the JS object is garbage-collected.| 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_ci## Example 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ciIf 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 lifecycle management APIs. 46e41f4b71Sopenharmony_ci 47e41f4b71Sopenharmony_ci### OH_JSVM_OpenHandleScope, OH_JSVM_CloseHandleScope 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ciUse **OH_JSVM_OpenHandleScope** to open a handle scope. Use **OH_JSVM_CloseHandleScope** to close a handle scope. Properly managing JS handle scopes can prevent GC problems. 50e41f4b71Sopenharmony_ci 51e41f4b71Sopenharmony_ciCPP code: 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci```cpp 54e41f4b71Sopenharmony_ci// hello.cpp 55e41f4b71Sopenharmony_ci#include "napi/native_api.h" 56e41f4b71Sopenharmony_ci#include "ark_runtime/jsvm.h" 57e41f4b71Sopenharmony_ci#include <hilog/log.h> 58e41f4b71Sopenharmony_ci// Register the HandleScopeTest, HandleScope, and HandleScopeFor callbacks. 59e41f4b71Sopenharmony_cistatic JSVM_CallbackStruct param[] = { 60e41f4b71Sopenharmony_ci {.data = nullptr, .callback = HandleScopeTest}, 61e41f4b71Sopenharmony_ci {.data = nullptr, .callback = HandleScope}, 62e41f4b71Sopenharmony_ci {.data = nullptr, .callback = HandleScopeFor}, 63e41f4b71Sopenharmony_ci}; 64e41f4b71Sopenharmony_cistatic JSVM_CallbackStruct *method = param; 65e41f4b71Sopenharmony_ci// Expose the HandleScopeTest, HandleScope, and HandleScopeFor callbacks to JS. 66e41f4b71Sopenharmony_cistatic JSVM_PropertyDescriptor descriptor[] = { 67e41f4b71Sopenharmony_ci {"handleScopeTest", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 68e41f4b71Sopenharmony_ci {"handleScope", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 69e41f4b71Sopenharmony_ci {"handleScopeFor", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 70e41f4b71Sopenharmony_ci}; 71e41f4b71Sopenharmony_cistatic int DIFF_VALUE_HUNDRED_THOUSAND = 100000; 72e41f4b71Sopenharmony_ci// Define OH_JSVM_OpenHandleScope and OH_JSVM_CloseHandleScope. 73e41f4b71Sopenharmony_cistatic JSVM_Value HandleScopeFor(JSVM_Env env, JSVM_CallbackInfo info) 74e41f4b71Sopenharmony_ci{ 75e41f4b71Sopenharmony_ci // When JSVM-API is frequently called to create JS objects in the for loop, use handle_scope to release resources in a timely manner when they are no longer required. 76e41f4b71Sopenharmony_ci // In the following example, the lifecycle of the local variable res ends at the end of each loop. To prevent memory leaks, scope is used to release the JS object in a timely manner. 77e41f4b71Sopenharmony_ci JSVM_Value checked = nullptr; 78e41f4b71Sopenharmony_ci for (int i = 0; i < DIFF_VALUE_HUNDRED_THOUSAND; i++) { 79e41f4b71Sopenharmony_ci JSVM_HandleScope scope = nullptr; 80e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_OpenHandleScope(env, &scope); 81e41f4b71Sopenharmony_ci if (status != JSVM_OK || scope == nullptr) { 82e41f4b71Sopenharmony_ci OH_JSVM_GetBoolean(env, false, &checked); 83e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_OpenHandleScope: failed"); 84e41f4b71Sopenharmony_ci return checked; 85e41f4b71Sopenharmony_ci } 86e41f4b71Sopenharmony_ci JSVM_Value res = nullptr; 87e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &res); 88e41f4b71Sopenharmony_ci status = OH_JSVM_CloseHandleScope(env, scope); 89e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 90e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_CloseHandleScope: failed"); 91e41f4b71Sopenharmony_ci } 92e41f4b71Sopenharmony_ci } 93e41f4b71Sopenharmony_ci OH_JSVM_GetBoolean(env, true, &checked); 94e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM HandleScopeFor: success"); 95e41f4b71Sopenharmony_ci return checked; 96e41f4b71Sopenharmony_ci} 97e41f4b71Sopenharmony_ci 98e41f4b71Sopenharmony_cistatic JSVM_Value HandleScopeTest(JSVM_Env env, JSVM_CallbackInfo info) 99e41f4b71Sopenharmony_ci{ 100e41f4b71Sopenharmony_ci // NOTE 101e41f4b71Sopenharmony_ci // In the following code, obj is created within the handle scope, which is later closed by OH_JSVM_OpenHandleScope. 102e41f4b71Sopenharmony_ci // After the handle scope is closed, results can still be returned normally 103e41f4b71Sopenharmony_ci // because the results are returned as the return values of functions, 104e41f4b71Sopenharmony_ci // instead of using obj outside the handle scope. 105e41f4b71Sopenharmony_ci // Call OH_JSVM_OpenHandleScope to create a handle scope. 106e41f4b71Sopenharmony_ci JSVM_HandleScope scope = nullptr; 107e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_OpenHandleScope(env, &scope); 108e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 109e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_OpenHandleScope: failed"); 110e41f4b71Sopenharmony_ci return nullptr; 111e41f4b71Sopenharmony_ci } 112e41f4b71Sopenharmony_ci // Create an object within the handle scope. 113e41f4b71Sopenharmony_ci JSVM_Value obj = nullptr; 114e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &obj); 115e41f4b71Sopenharmony_ci // Add properties to the object. 116e41f4b71Sopenharmony_ci JSVM_Value value = nullptr; 117e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "test handleScope", JSVM_AUTO_LENGTH, &value); 118e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "name", value); 119e41f4b71Sopenharmony_ci // Close the handle scope. Then, the object handles created within the scope are automatically released. 120e41f4b71Sopenharmony_ci status = OH_JSVM_CloseHandleScope(env, scope); 121e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 122e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_CloseHandleScope: failed"); 123e41f4b71Sopenharmony_ci return nullptr; 124e41f4b71Sopenharmony_ci } 125e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM HandleScopeTest: success"); 126e41f4b71Sopenharmony_ci return obj; 127e41f4b71Sopenharmony_ci} 128e41f4b71Sopenharmony_ci 129e41f4b71Sopenharmony_cistatic JSVM_Value HandleScope(JSVM_Env env, JSVM_CallbackInfo info) 130e41f4b71Sopenharmony_ci{ 131e41f4b71Sopenharmony_ci // Call OH_JSVM_OpenHandleScope to create a handle scope. 132e41f4b71Sopenharmony_ci JSVM_HandleScope scope = nullptr; 133e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_OpenHandleScope(env, &scope); 134e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 135e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_OpenHandleScope: failed"); 136e41f4b71Sopenharmony_ci return nullptr; 137e41f4b71Sopenharmony_ci } 138e41f4b71Sopenharmony_ci // Create an object within the handle scope. 139e41f4b71Sopenharmony_ci JSVM_Value obj = nullptr; 140e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &obj); 141e41f4b71Sopenharmony_ci // Add properties to the object. 142e41f4b71Sopenharmony_ci JSVM_Value value = nullptr; 143e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "handleScope", JSVM_AUTO_LENGTH, &value); 144e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "name", value); 145e41f4b71Sopenharmony_ci // Close the handle scope. Then, the object handles created within the scope are automatically released. 146e41f4b71Sopenharmony_ci status = OH_JSVM_CloseHandleScope(env, scope); 147e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 148e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_CloseHandleScope: failed"); 149e41f4b71Sopenharmony_ci return nullptr; 150e41f4b71Sopenharmony_ci } 151e41f4b71Sopenharmony_ci // After the handle scope is closed, add properties to the object. The previously set property 'name' becomes invalid. 152e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "001", JSVM_AUTO_LENGTH, &value); 153e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "id", value); 154e41f4b71Sopenharmony_ci // The property 'name' is invalid. 155e41f4b71Sopenharmony_ci bool result = true; 156e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "name", JSVM_AUTO_LENGTH, &value); 157e41f4b71Sopenharmony_ci OH_JSVM_HasProperty(env, obj, value, &result); 158e41f4b71Sopenharmony_ci if (!result) { 159e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM HandleScope: success"); 160e41f4b71Sopenharmony_ci } 161e41f4b71Sopenharmony_ci return obj; 162e41f4b71Sopenharmony_ci} 163e41f4b71Sopenharmony_ci``` 164e41f4b71Sopenharmony_ci 165e41f4b71Sopenharmony_ciArkTS code: 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci```ts 168e41f4b71Sopenharmony_ciimport hilog from "@ohos.hilog" 169e41f4b71Sopenharmony_ci// Import the native APIs. 170e41f4b71Sopenharmony_ciimport napitest from "libentry.so" 171e41f4b71Sopenharmony_citry { 172e41f4b71Sopenharmony_ci let script: string = `handleScopeTest()`; 173e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 174e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM handleScopeTest: %{public}s', result); 175e41f4b71Sopenharmony_ci} catch (error) { 176e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM handleScopeTest error: %{public}s', error.message); 177e41f4b71Sopenharmony_ci} 178e41f4b71Sopenharmony_citry { 179e41f4b71Sopenharmony_ci let script: string = `handleScope()`; 180e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 181e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM handleScope: %{public}s', result); 182e41f4b71Sopenharmony_ci} catch (error) { 183e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM handleScope error: %{public}s', error.message); 184e41f4b71Sopenharmony_ci} 185e41f4b71Sopenharmony_citry { 186e41f4b71Sopenharmony_ci let script: string = `handleScopeFor()`; 187e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 188e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM handleScopeFor: %{public}s', result); 189e41f4b71Sopenharmony_ci} catch (error) { 190e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM handleScopeFor error: %{public}s', error.message); 191e41f4b71Sopenharmony_ci} 192e41f4b71Sopenharmony_ci``` 193e41f4b71Sopenharmony_ci 194e41f4b71Sopenharmony_ci### OH_JSVM_OpenEscapableHandleScope, OH_JSVM_CloseEscapableHandleScope, OH_JSVM_EscapeHandle 195e41f4b71Sopenharmony_ci 196e41f4b71Sopenharmony_ciUse **OH_JSVM_OpenEscapableHandleScope** to create an escapeable handle scope, which allows the declared values in the scope to be returned to the parent scope. Use **OH_JSVM_CloseEscapableHandleScope** to close an escapeable handle scope. Use **OH_JSVM_EscapeHandle** to promote the lifecycle of a JS object so that it is valid for the lifetime of the outer scope. 197e41f4b71Sopenharmony_ciThese APIs are helpful for managing ArkTS objects more flexibly in C/C++, especially when passing cross-scope values. 198e41f4b71Sopenharmony_ci 199e41f4b71Sopenharmony_ciCPP code: 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci```cpp 202e41f4b71Sopenharmony_ci// hello.cpp 203e41f4b71Sopenharmony_ci#include "napi/native_api.h" 204e41f4b71Sopenharmony_ci#include "ark_runtime/jsvm.h" 205e41f4b71Sopenharmony_ci#include <hilog/log.h> 206e41f4b71Sopenharmony_ci// Define the EscapableHandleScopeTest callback. 207e41f4b71Sopenharmony_cistatic JSVM_CallbackStruct param[] = { 208e41f4b71Sopenharmony_ci {.data = nullptr, .callback = EscapableHandleScopeTest}, 209e41f4b71Sopenharmony_ci}; 210e41f4b71Sopenharmony_cistatic JSVM_CallbackStruct *method = param; 211e41f4b71Sopenharmony_ci// Set a property descriptor named escapableHandleScopeTest and associate it with a callback. This allows the EscapableHandleScopeTest callback to be called from JS. 212e41f4b71Sopenharmony_cistatic JSVM_PropertyDescriptor descriptor[] = { 213e41f4b71Sopenharmony_ci {"escapableHandleScopeTest", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 214e41f4b71Sopenharmony_ci}; 215e41f4b71Sopenharmony_ci// Define OH_JSVM_OpenEscapableHandleScope, OH_JSVM_CloseEscapableHandleScope, and OH_JSVM_EscapeHandle. 216e41f4b71Sopenharmony_cistatic JSVM_Value EscapableHandleScopeTest(JSVM_Env env, JSVM_CallbackInfo info) 217e41f4b71Sopenharmony_ci{ 218e41f4b71Sopenharmony_ci // Create an escapeable handle scope. 219e41f4b71Sopenharmony_ci JSVM_EscapableHandleScope scope = nullptr; 220e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_OpenEscapableHandleScope(env, &scope); 221e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 222e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_OpenEscapableHandleScope: failed"); 223e41f4b71Sopenharmony_ci return nullptr; 224e41f4b71Sopenharmony_ci } 225e41f4b71Sopenharmony_ci // Create an object within the scope of the escapeable handle. 226e41f4b71Sopenharmony_ci JSVM_Value obj; 227e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &obj); 228e41f4b71Sopenharmony_ci // Add properties to the object. 229e41f4b71Sopenharmony_ci JSVM_Value value = nullptr; 230e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "Test jsvm_escapable_handle_scope", JSVM_AUTO_LENGTH, &value); 231e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "name", value); 232e41f4b71Sopenharmony_ci // Call OH_JSVM_EscapeHandle to promote the JS object handle to make it valid with the lifetime of the outer scope. 233e41f4b71Sopenharmony_ci JSVM_Value escapedObj = nullptr; 234e41f4b71Sopenharmony_ci OH_JSVM_EscapeHandle(env, scope, obj, &escapedObj); 235e41f4b71Sopenharmony_ci // Close the escapeable handle scope to clear resources. 236e41f4b71Sopenharmony_ci status = OH_JSVM_CloseEscapableHandleScope(env, scope); 237e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 238e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_CloseEscapableHandleScope: failed"); 239e41f4b71Sopenharmony_ci return nullptr; 240e41f4b71Sopenharmony_ci } 241e41f4b71Sopenharmony_ci // Use escapedObj outside the scope. Since escapedObj has escaped, the property can be set successfully and obtained from ArkTs. 242e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "001", JSVM_AUTO_LENGTH, &value); 243e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "id", value); 244e41f4b71Sopenharmony_ci bool result = false; 245e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "id", JSVM_AUTO_LENGTH, &value); 246e41f4b71Sopenharmony_ci OH_JSVM_HasProperty(env, obj, value, &result); 247e41f4b71Sopenharmony_ci if (result) { 248e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM EscapableHandleScopeTest: success"); 249e41f4b71Sopenharmony_ci } 250e41f4b71Sopenharmony_ci return escapedObj; 251e41f4b71Sopenharmony_ci} 252e41f4b71Sopenharmony_ci``` 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci 255e41f4b71Sopenharmony_ci 256e41f4b71Sopenharmony_ciArkTS code: 257e41f4b71Sopenharmony_ci 258e41f4b71Sopenharmony_ci```ts 259e41f4b71Sopenharmony_ciimport hilog from "@ohos.hilog" 260e41f4b71Sopenharmony_ci// Import the native APIs. 261e41f4b71Sopenharmony_ciimport napitest from "libentry.so" 262e41f4b71Sopenharmony_citry { 263e41f4b71Sopenharmony_ci let script: string = `escapableHandleScopeTest()`; 264e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 265e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM escapableHandleScopeTest: %{public}s', result); 266e41f4b71Sopenharmony_ci} catch (error) { 267e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM escapableHandleScopeTest error: %{public}s', error.message); 268e41f4b71Sopenharmony_ci} 269e41f4b71Sopenharmony_ci``` 270e41f4b71Sopenharmony_ci 271e41f4b71Sopenharmony_ci### OH_JSVM_CreateReference, OH_JSVM_DeleteReference 272e41f4b71Sopenharmony_ci 273e41f4b71Sopenharmony_ciUse **OH_JSVM_CreateReference** to create a reference for an object to extend its lifespan. The caller needs to manage the reference lifespan. Use **OH_JSVM_DeleteReference** to delete a reference. 274e41f4b71Sopenharmony_ci 275e41f4b71Sopenharmony_ci### OH_JSVM_ReferenceRef, OH_JSVM_ReferenceUnref 276e41f4b71Sopenharmony_ci 277e41f4b71Sopenharmony_ciUse **OH_JSVM_ReferenceRef** to increment the reference count of a reference and use **OH_JSVM_ReferenceUnref** to decrement the reference count of a reference, and return the new count value. 278e41f4b71Sopenharmony_ci 279e41f4b71Sopenharmony_ci### OH_JSVM_GetReferenceValue 280e41f4b71Sopenharmony_ci 281e41f4b71Sopenharmony_ciUse **OH_JSVM_GetReferenceValue** to obtain the JS object associated with the reference. 282e41f4b71Sopenharmony_ci 283e41f4b71Sopenharmony_ci### OH_JSVM_AddFinalizer 284e41f4b71Sopenharmony_ci 285e41f4b71Sopenharmony_ciUse **OH_JSVM_AddFinalizer** to add a **JSVM_Finalize** callback, which will be called when the JS object is garbage-collected. 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ciCPP code: 288e41f4b71Sopenharmony_ci 289e41f4b71Sopenharmony_ci```cpp 290e41f4b71Sopenharmony_ci// hello.cpp 291e41f4b71Sopenharmony_ci#include "napi/native_api.h" 292e41f4b71Sopenharmony_ci#include "ark_runtime/jsvm.h" 293e41f4b71Sopenharmony_ci#include <hilog/log.h> 294e41f4b71Sopenharmony_ci// Register the CreateReference, UseReference, and DeleteReference callbacks. 295e41f4b71Sopenharmony_cistatic JSVM_CallbackStruct param[] = { 296e41f4b71Sopenharmony_ci {.data = nullptr, .callback = CreateReference}, 297e41f4b71Sopenharmony_ci {.data = nullptr, .callback = UseReference}, 298e41f4b71Sopenharmony_ci {.data = nullptr, .callback = DeleteReference}, 299e41f4b71Sopenharmony_ci}; 300e41f4b71Sopenharmony_cistatic JSVM_CallbackStruct *method = param; 301e41f4b71Sopenharmony_ci// Expose the CreateReference, UseReference, and DeleteReference callbacks to JS. 302e41f4b71Sopenharmony_cistatic JSVM_PropertyDescriptor descriptor[] = { 303e41f4b71Sopenharmony_ci {"createReference", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 304e41f4b71Sopenharmony_ci {"useReference", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 305e41f4b71Sopenharmony_ci {"deleteReference", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 306e41f4b71Sopenharmony_ci}; 307e41f4b71Sopenharmony_ci// Define OH_JSVM_CreateReference and OH_JSVM_AddFinalizer. 308e41f4b71Sopenharmony_cistatic JSVM_Value CreateReference(JSVM_Env env, JSVM_CallbackInfo info) 309e41f4b71Sopenharmony_ci{ 310e41f4b71Sopenharmony_ci JSVM_Ref g_ref = nullptr; 311e41f4b71Sopenharmony_ci JSVM_Value obj = nullptr; 312e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &obj); 313e41f4b71Sopenharmony_ci JSVM_Value value = nullptr; 314e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "CreateReference", JSVM_AUTO_LENGTH, &value); 315e41f4b71Sopenharmony_ci // Add a property to the object. 316e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "name", value); 317e41f4b71Sopenharmony_ci // Create a reference to the JS object. 318e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_CreateReference(env, obj, 1, &g_ref); 319e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 320e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_CreateReference: failed"); 321e41f4b71Sopenharmony_ci return nullptr; 322e41f4b71Sopenharmony_ci } 323e41f4b71Sopenharmony_ci JSVM_Finalize jSVM_Finalize = nullptr; 324e41f4b71Sopenharmony_ci OH_JSVM_AddFinalizer(env, obj, nullptr, jSVM_Finalize, nullptr, &g_ref); 325e41f4b71Sopenharmony_ci // Increment the reference count and return the new reference count. 326e41f4b71Sopenharmony_ci uint32_t result; 327e41f4b71Sopenharmony_ci OH_JSVM_ReferenceRef(env, g_ref, &result); 328e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_ReferenceRef, count = %{public}d.", result); 329e41f4b71Sopenharmony_ci if (result != 2) { 330e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_ReferenceRef: failed"); 331e41f4b71Sopenharmony_ci return nullptr; 332e41f4b71Sopenharmony_ci } 333e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM CreateReference success"); 334e41f4b71Sopenharmony_ci return obj; 335e41f4b71Sopenharmony_ci} 336e41f4b71Sopenharmony_ci// Define OH_JSVM_ReferenceRef and OH_JSVM_GetReferenceValue. 337e41f4b71Sopenharmony_cistatic JSVM_Value UseReference(JSVM_Env env, JSVM_CallbackInfo info) 338e41f4b71Sopenharmony_ci{ 339e41f4b71Sopenharmony_ci JSVM_Ref g_ref = nullptr; 340e41f4b71Sopenharmony_ci JSVM_Value obj = nullptr; 341e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &obj); 342e41f4b71Sopenharmony_ci JSVM_Value value = nullptr; 343e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "UseReference", JSVM_AUTO_LENGTH, &value); 344e41f4b71Sopenharmony_ci // Add a property to the object. 345e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "name", value); 346e41f4b71Sopenharmony_ci // Create a reference to the JS object. 347e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_CreateReference(env, obj, 1, &g_ref); 348e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 349e41f4b71Sopenharmony_ci return nullptr; 350e41f4b71Sopenharmony_ci } 351e41f4b71Sopenharmony_ci JSVM_Finalize jSVM_Finalize = nullptr; 352e41f4b71Sopenharmony_ci OH_JSVM_AddFinalizer(env, obj, nullptr, jSVM_Finalize, nullptr, &g_ref); 353e41f4b71Sopenharmony_ci // Increment the reference count and return the new reference count. 354e41f4b71Sopenharmony_ci uint32_t result; 355e41f4b71Sopenharmony_ci OH_JSVM_ReferenceRef(env, g_ref, &result); 356e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_ReferenceRef, count = %{public}d.", result); 357e41f4b71Sopenharmony_ci if (result != 2) { 358e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_ReferenceRef: failed"); 359e41f4b71Sopenharmony_ci return nullptr; 360e41f4b71Sopenharmony_ci } 361e41f4b71Sopenharmony_ci JSVM_Value object = nullptr; 362e41f4b71Sopenharmony_ci // Call OH_JSVM_GetReferenceValue to obtain the referenced JS object. 363e41f4b71Sopenharmony_ci status = OH_JSVM_GetReferenceValue(env, g_ref, &object); 364e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 365e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_GetReferenceValue: failed"); 366e41f4b71Sopenharmony_ci return nullptr; 367e41f4b71Sopenharmony_ci } 368e41f4b71Sopenharmony_ci // Return the obtained object. 369e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM UseReference success"); 370e41f4b71Sopenharmony_ci return object; 371e41f4b71Sopenharmony_ci} 372e41f4b71Sopenharmony_ci// Define OH_JSVM_ReferenceUnref and OH_JSVM_DeleteReference. 373e41f4b71Sopenharmony_cistatic JSVM_Value DeleteReference(JSVM_Env env, JSVM_CallbackInfo info) 374e41f4b71Sopenharmony_ci{ 375e41f4b71Sopenharmony_ci JSVM_Ref g_ref = nullptr; 376e41f4b71Sopenharmony_ci JSVM_Value obj = nullptr; 377e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &obj); 378e41f4b71Sopenharmony_ci JSVM_Value value = nullptr; 379e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "DeleteReference", JSVM_AUTO_LENGTH, &value); 380e41f4b71Sopenharmony_ci // Add a property to the object. 381e41f4b71Sopenharmony_ci OH_JSVM_SetNamedProperty(env, obj, "name", value); 382e41f4b71Sopenharmony_ci // Create a reference to the JS object. 383e41f4b71Sopenharmony_ci JSVM_Status status = OH_JSVM_CreateReference(env, obj, 1, &g_ref); 384e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 385e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_CreateReference: failed"); 386e41f4b71Sopenharmony_ci return nullptr; 387e41f4b71Sopenharmony_ci } 388e41f4b71Sopenharmony_ci JSVM_Finalize jSVM_Finalize = nullptr; 389e41f4b71Sopenharmony_ci OH_JSVM_AddFinalizer(env, obj, nullptr, jSVM_Finalize, nullptr, &g_ref); 390e41f4b71Sopenharmony_ci // Increment the reference count and return the new reference count. 391e41f4b71Sopenharmony_ci uint32_t result; 392e41f4b71Sopenharmony_ci OH_JSVM_ReferenceRef(env, g_ref, &result); 393e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_ReferenceRef, count = %{public}d.", result); 394e41f4b71Sopenharmony_ci if (result != 2) { 395e41f4b71Sopenharmony_ci return nullptr; 396e41f4b71Sopenharmony_ci } 397e41f4b71Sopenharmony_ci // Decrement the reference count and return the new reference count. 398e41f4b71Sopenharmony_ci uint32_t num; 399e41f4b71Sopenharmony_ci OH_JSVM_ReferenceUnref(env, g_ref, &num); 400e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM OH_JSVM_ReferenceUnref, count = %{public}d.", num); 401e41f4b71Sopenharmony_ci if (num != 1) { 402e41f4b71Sopenharmony_ci return nullptr; 403e41f4b71Sopenharmony_ci } 404e41f4b71Sopenharmony_ci // Call OH_JSVM_DeleteReference to delete the reference to the JS object. 405e41f4b71Sopenharmony_ci status = OH_JSVM_DeleteReference(env, g_ref); 406e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 407e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM OH_JSVM_DeleteReference: failed"); 408e41f4b71Sopenharmony_ci return nullptr; 409e41f4b71Sopenharmony_ci } 410e41f4b71Sopenharmony_ci JSVM_Value returnResult = nullptr; 411e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, "OH_JSVM_DeleteReference success", JSVM_AUTO_LENGTH, &returnResult); 412e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM DeleteReference success"); 413e41f4b71Sopenharmony_ci return returnResult; 414e41f4b71Sopenharmony_ci} 415e41f4b71Sopenharmony_ci``` 416e41f4b71Sopenharmony_ci 417e41f4b71Sopenharmony_ciArkTS code: 418e41f4b71Sopenharmony_ci 419e41f4b71Sopenharmony_ci```ts 420e41f4b71Sopenharmony_ciimport hilog from "@ohos.hilog" 421e41f4b71Sopenharmony_ci// Import the native APIs. 422e41f4b71Sopenharmony_ciimport napitest from "libentry.so" 423e41f4b71Sopenharmony_citry { 424e41f4b71Sopenharmony_ci let script: string = `createReference();`; 425e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 426e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM createReference: %{public}s', result); 427e41f4b71Sopenharmony_ci} catch (error) { 428e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM createReference error: %{public}s', error.message); 429e41f4b71Sopenharmony_ci} 430e41f4b71Sopenharmony_citry { 431e41f4b71Sopenharmony_ci let script: string = `useReference();`; 432e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 433e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM useReference: %{public}s', result); 434e41f4b71Sopenharmony_ci} catch (error) { 435e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM useReference error: %{public}s', error.message); 436e41f4b71Sopenharmony_ci} 437e41f4b71Sopenharmony_citry { 438e41f4b71Sopenharmony_ci let script: string = `deleteReference();`; 439e41f4b71Sopenharmony_ci let result = napitest.runJsVm(script); 440e41f4b71Sopenharmony_ci hilog.info(0x0000, 'testJSVM', 'Test JSVM deleteReference: %{public}s', result); 441e41f4b71Sopenharmony_ci} catch (error) { 442e41f4b71Sopenharmony_ci hilog.error(0x0000, 'testJSVM', 'Test JSVM deleteReference error: %{public}s', error.message); 443e41f4b71Sopenharmony_ci} 444e41f4b71Sopenharmony_ci``` 445