1# JSVM-API支持的数据类型和接口
2
3## JSVM-API的数据类型
4
5### JSVM_Status
6
7是一个枚举数据类型,表示JSVM-API接口返回的状态信息。
8
9每当调用一个JSVM-API函数,都会返回该值,表示操作成功与否的相关信息。
10
11```c++
12typedef enum {
13    JSVM_OK,
14    JSVM_INVALID_ARG,
15    JSVM_OBJECT_EXPECTED,
16    JSVM_STRING_EXPECTED,
17    JSVM_NAME_EXPECTED,
18    JSVM_FUNCTION_EXPECTED,
19    JSVM_NUMBER_EXPECTED,
20    JSVM_BOOL_EXPECTED,
21    JSVM_ARRAY_EXPECTED,
22    JSVM_GENERIC_FAILURE,
23    JSVM_PENDING_EXCEPTION,
24    JSVM_CENCELLED,
25    JSVM_ESCAPE_CALLED_TWICE,
26    JSVM_HANDLE_SCOPE_MISMATCH,
27    JSVM_CALLBACK_SCOPE_MISMATCH,
28    JSVM_QUEUE_FULL,
29    JSVM_CLOSING,
30    JSVM_BIGINT_EXPECTED,
31    JSVM_DATA_EXPECTED,
32    JSVM_CALLBACK_SCOPE_MISMATCH,
33    JSVM_DETACHABLE_ARRAYBUFFER_EXPECTED,
34    JSVM_WOULD_DEADLOCK,  /* unused */
35    JSVM_NO_EXTERNAL_BUFFERS_ALLOWED,
36    JSVM_CANNOT_RUN_JS
37} JSVM_Status;
38```
39
40### JSVM_ExtendedErrorInfo
41
42一个结构体,在调用函数不成功时存储了较为详细的错误信息。
43
44```c++
45typedef struct {
46    const char* errorMessage;
47    void* engineReserved;
48    uint32_t engineErrorCode;
49    JSVM_Status errorCode;
50} JSVM_ExtendedErrorInfo;
51```
52
53### JSVM_Value
54
55在C++代码中,表示一个JavaScript值。
56
57### JSVM_Env
58
59- 用于表示JSVM-API执行时的上下文,Native侧函数入参,并传递给函数中的JSVM-API接口。
60
61- 退出Native侧插件时,JSVM_Env将失效,该事件通过回调传递给OH_JSVM_SetInstanceData。
62
63- 禁止缓存JSVM_Env,禁止在不同Worker中传递JSVM_Env。
64
65- 在不同线程间共享JSVM_Env时,要保证在线程切换时在前一个线程中关闭env scope并在新的线程中打开新的env scope,以保证threadlocal变量的线程隔离。
66
67### JSVM_ValueType
68
69JSVM_Value的类型。包含了ECMAScript语言规范中定义的类型,其中JSVM_EXTERNAL表示外部数据类型。
70
71```c++
72typedef enum {
73    JSVM_UNDEFINED,
74    JSVM_NULL,
75    JSVM_BOOLEAN,
76    JSVM_NUMBER,
77    JSVM_STRING,
78    JSVM_SYMBOL,
79    JSVM_OBJECT,
80    JSVM_FUNCTION,
81    JSVM_EXTERNAL,
82    JSVM_BIGINT,
83} JSVM_ValueType;
84```
85
86### JSVM_TypedarrayType
87
88TypedArray的基本二进制标量数据类型。
89
90```c++
91typedef enum {
92    JSVM_INT8_ARRAY,
93    JSVM_UINT8_ARRAY,
94    JSVM_UINT8_CLAMPED_ARRAY,
95    JSVM_INT16_ARRAY,
96    JAVM_UINT16_ARRAY,
97    JSVM_INT32_ARRAY,
98    JSVM_UINT32_ARRAY,
99    JSVM_FLOAT32_ARRAY,
100    JSVM_FLOAT64_ARRAY,
101    JSVM_BIGINT64_ARRAY,
102    JSVM_BIGUINT64_ARRAY,
103} JSVM_TypedarrayType;
104```
105
106### JSVM_RegExpFlags
107
108正则表达式标志位。
109
110```c++
111typedef enum {
112    JSVM_REGEXP_NONE = 0,
113    JSVM_REGEXP_GLOBAL = 1 << 0,
114    JSVM_REGEXP_IGNORE_CASE = 1 << 1,
115    JSVM_REGEXP_MULTILINE = 1 << 2,
116    JSVM_REGEXP_STICKY = 1 << 3,
117    JSVM_REGEXP_UNICODE = 1 << 4,
118    JSVM_REGEXP_DOT_ALL = 1 << 5,
119    JSVM_REGEXP_LINEAR = 1 << 6,
120    JSVM_REGEXP_HAS_INDICES = 1 << 7,
121    JSVM_REGEXP_UNICODE_SETS = 1 << 8,
122} JSVM_RegExpFlags;
123```
124
125### 编译选项相关类型
126#### JSVM_CompileOptions
127
128配合编译接口 OH_JSVM_CompileScriptWithOptions 使用,是其参数中 options 数组的元素类型。
129
130其中:
131- id 代表这个编译选项的类型。
132- content 代表编译选项的内容。
133
134id 的值和 content 的类型需要对应使用,详细对应关系参考下面对各个选项类型的介绍。
135
136```c
137typedef struct {
138    /** compile option id. */
139    JSVM_CompileOptionId id;
140    /** option content. */
141    union {
142      /** ptr type. */
143      void *ptr;
144      /** int type. */
145      int num;
146      /** bool type. */
147      _Bool boolean;
148    } content;
149} JSVM_CompileOptions;
150```
151
152#### JSVM_CompileOptionId
153
154JSVM_CompileOptions 中的 id 对应类型, 每个值都有其对应的 content 类型, 其中 JSVM_COMPILE_ENABLE_SOURCE_MAP 对应的类型为 bool,当同时传入的 JSVM_ScriptOrigin 中 sourceMapUrl 不为空时生效。
155
156```c
157typedef enum {
158    /** compile mode. */
159    JSVM_COMPILE_MODE,
160    /** code cache content. */
161    JSVM_COMPILE_CODE_CACHE,
162    /** script origin. */
163    JSVM_COMPILE_SCRIPT_ORIGIN,
164    /** compile profile content. */
165    JSVM_COMPILE_COMPILE_PROFILE,
166    /** switch for source map support. */
167    JSVM_COMPILE_ENABLE_SOURCE_MAP,
168} JSVM_CompileOptionId;
169```
170
171#### JSVM_CompileMode
172
173当 id 为 JSVM_COMPILE_MODE,content 的类型,每个值代表一种编译模式:
174
175- JSVM_COMPILE_MODE_DEFAULT : 默认的编译选项。
176- JSVM_COMPILE_MODE_CONSUME_CODE_CACHE : 消耗 codecache 进行编译。
177- JSVM_COMPILE_MODE_EAGER_COMPILE : 进行全量编译,不再进行 lazy compile。
178- JSVM_COMPILE_MODE_PRODUCE_COMPILE_PROFILE/JSVM_COMPILE_MODE_CONSUME_COMPILE_PROFILE : 当前暂无效果,请等待后续更新。
179
180```c
181typedef enum {
182    /** default mode. */
183    JSVM_COMPILE_MODE_DEFAULT,
184    /** consume code cache. */
185    JSVM_COMPILE_MODE_CONSUME_CODE_CACHE,
186    /** apply eager compile. */
187    JSVM_COMPILE_MODE_EAGER_COMPILE,
188    /** preset for compile profile. */
189    JSVM_COMPILE_MODE_PRODUCE_COMPILE_PROFILE,
190    /** consume compile profile. */
191    JSVM_COMPILE_MODE_CONSUME_COMPILE_PROFILE,
192} JSVM_CompileMode;
193```
194
195
196#### JSVM_CodeCache
197
198当 id 为 JSVM_COMPILE_CODE_CACHE 时,content 的类型:
199
200- cache : 指向 code cache 的指针。
201- length : code cache 的大小。
202
203```c
204typedef struct {
205    /** cache pointer. */
206    uint8_t *cache;
207    /** length. */
208    size_t length;
209} JSVM_CodeCache;
210```
211
212#### JSVM_ScriptOrigin
213
214当 id 为 JSVM_COMPILE_SCRIPT_ORIGIN 时,content 的类型,存放待编译脚本的源码信息:
215
216- sourceMapUrl : sourceMap 的路径,当前仅支持运行设备上的本地路径, 可以为空。
217- resourceName : 待编译的 js script 的名字。
218
219```c
220typedef struct {
221    /** Sourcemap url. */
222    const char* sourceMapUrl;
223    /** Resource name. */
224    const char* resourceName;
225    /** Resource line offset. */
226    size_t resourceLineOffset;
227    /** Resource column offset. */
228    size_t resourceColumnOffset;
229} JSVM_ScriptOrigin;
230```
231
232### JSVM
233### 内存管理类型
234
235JSVM-API包含以下内存管理类型:
236
237**JSVM_HandleScope**
238
239JSVM_HandleScope数据类型是用来管理JavaScript对象的生命周期的。它允许JavaScript对象在一定范围内保持活动状态,以便在JavaScript代码中使用。在创建JSVM_HandleScope时,所有在该范围内创建的JavaScript对象都会保持活动状态,直到结束。这样可以避免在JavaScript代码中使用已经被释放的对象,从而提高代码的可靠性和性能
240
241**JSVM_EscapableHandleScope**
242
243- 由OH_JSVM_OpenEscapableHandleScope接口创建,由OH_JSVM_CloseEscapableHandleScope接口关闭。
244
245- 表示一种特殊类型的句柄范围,用于将在JSVM_EscapableHandleScope范围内创建的值返回给父scope。
246
247- 用于OH_JSVM_EscapeHandle接口,将JSVM_EscapableHandleScope提升到JavaScript对象,以便在外部作用域使用。
248
249**JSVM_Ref**
250
251指向JSVM_Value,允许用户管理JavaScript值的生命周期。
252
253**JSVM_TypeTag**
254
255该结构体定义了一个包含两个无符号64位整数的类型标签,用于标识一个JSVM-API值的类型信息。
256
257```c++
258typedef struct {
259    uint64_t lower;
260    uint64_t upper;
261} JSVM_TypeTag;
262```
263
264- 存储了两个无符号64位整数的128位值,用它来标记JavaScript对象,确保它们属于某种类型。
265
266- 比OH_JSVM_Instanceof更强的类型检查,如果对象的原型被操纵,OH_JSVM_Instanceof可能会报告误报。
267
268- JSVM_TypeTag 在与 OH_JSVM_Wrap 结合使用时最有用,因为它确保从包装对象检索的指针可以安全地转换为与先前应用于JavaScript对象的类型标记相对应的Native类型。
269
270### 回调类型
271
272JSVM-API包含以下回调类型:
273
274**JSVM_CallbackStruct**
275
276用户提供的 Native callback 的回调函数指针和数据,JSVM_CallbackStruct 将通过 JSVM-API 暴露给 JavaScript。例如,可以使用 OH_JSVM_CreateFunction 接口创建绑定到 Native callback 的 JS 函数,其中 Native callback 就是通过 JSVM_CallbackStruct 结构定义。除非在对象生命周期管理中有特殊要求,一般不在此 callback 中创建 handle 或者 callback scope。
277
278```c++
279typedef struct {
280  JSVM_Value(*callback)(JSVM_Env env, JSVM_CallbackInfo info);
281  void* data;
282} JSVM_CallbackStruct;
283```
284
285**JSVM_Callback**
286
287JSVM_CallbackStruct 指针类型的类型别名。
288
289定义如下:
290
291```c++
292typedef JSVM_CallbackStruct* JSVM_Callback;
293```
294
295**JSVM_CallbackInfo**
296
297用户定义的 Native callback,第一个参数类型是 JSVM_Env,第二个参数类型是 JSVM_CallbackInfo。JSVM_CallbackInfo 表示从 JS 侧调用到 Native 侧时携带的调用信息,如参数列表。在实现 Native callback 时,一般使用 OH_JSVM_GetCbInfo 接口从 JSVM_CallbackInfo 中提取调用信息。
298
299**JSVM_Finalize**
300
301函数指针,用于传入OH_JSVM_SetInstanceData、OH_JSVM_CreateExternal、OH_JSVM_Wrap等接口。JSVM_Finalize在对象被回收时会被调用,可用于在JavaScript对象被垃圾回收时释放Native对象。
302
303写法如下:
304
305```c++
306typedef void (*JSVM_Finalize)(JSVM_Env env, void* finalizeData, void* finalizeHint);
307```
308
309**JSVM_PropertyHandlerConfigurationStruct**
310
311当执行对象的getter、setter、deleter和enumerator作时,对应的的回调将会触发。
312
313```c++
314typedef struct {
315    JSVM_Value(JSVM_CDECL* genericNamedPropertyGetterCallback)(JSVM_Env env,
316                                                               JSVM_Value name,
317                                                               JSVM_Value thisArg,
318                                                               JSVM_Value namedPropertyData);
319    JSVM_Value(JSVM_CDECL* genericNamedPropertySetterCallback)(JSVM_Env env,
320                                                               JSVM_Value name,
321                                                               JSVM_Value property,
322                                                               JSVM_Value thisArg,
323                                                               JSVM_Value namedPropertyData);
324    JSVM_Value(JSVM_CDECL* genericNamedPropertyDeleterCallback)(JSVM_Env env,
325                                                                JSVM_Value name,
326                                                                JSVM_Value thisArg,
327                                                                JSVM_Value namedPropertyData);
328    JSVM_Value(JSVM_CDECL* genericNamedPropertyEnumeratorCallback)(JSVM_Env env,
329                                                                   JSVM_Value thisArg,
330                                                                   JSVM_Value namedPropertyData);
331    JSVM_Value(JSVM_CDECL* genericIndexedPropertyGetterCallback)(JSVM_Env env,
332                                                                JSVM_Value index,
333                                                                JSVM_Value thisArg,
334                                                                JSVM_Value indexedPropertyData);
335    JSVM_Value(JSVM_CDECL* genericIndexedPropertySetterCallback)(JSVM_Env env,
336                                                                 JSVM_Value index,
337                                                                 JSVM_Value property,
338                                                                 JSVM_Value thisArg,
339                                                                 JSVM_Value indexedPropertyData);
340    JSVM_Value(JSVM_CDECL* genericIndexedPropertyDeleterCallback)(JSVM_Env env,
341                                                                  JSVM_Value index,
342                                                                  JSVM_Value thisArg,
343                                                                  JSVM_Value indexedPropertyData);
344    JSVM_Value(JSVM_CDECL* genericIndexedPropertyEnumeratorCallback)(JSVM_Env env,
345                                                                     JSVM_Value thisArg,
346                                                                     JSVM_Value indexedPropertyData);
347    JSVM_Value namedPropertyData;
348    JSVM_Value indexedPropertyData;
349} JSVM_PropertyHandlerConfigurationStruct;
350```
351
352**JSVM_PropertyHandlerCfg**
353
354包含属性监听回调的结构的指针类型。
355
356基本用法如下:
357
358```c++
359typedef JSVM_PropertyHandlerConfigurationStruct* JSVM_PropertyHandlerCfg;
360```
361
362## 支持的JSVM-API接口
363
364标准JS引擎的能力通过JSVM-API提供。JSVM-API支持动态链接到不同版本的JS引擎库,从而为开发者屏蔽掉不同引擎接口的差异。JSVM-API提供引擎生命周期管理、JS context管理、JS代码执行、JS/C++互操作、执行环境快照、codecache等能力,具体可见下文。
365
366### 使用 JSVM-API 接口创建引擎实例及 JS 执行上下文环境
367
368#### 场景介绍
369
370执行JS代码需要先创建JavaScript VM,创建JS执行的上下文环境。
371
372#### 接口说明
373| 接口 | 功能说明 |
374| -------- | -------- |
375| OH_JSVM_Init| 初始化JavaScript引擎实例 |
376| OH_JSVM_CreateVM| 创建JavaScript引擎实例|
377| OH_JSVM_DestroyVM| 销毁JavaScript引擎实例 |
378| OH_JSVM_OpenVMScope| 打开一个新的VM scope,引擎实例只能在scope范围内使用,可以保证引擎实例不被销毁 |
379| OH_JSVM_CloseVMScope| 关闭VM scope |
380| OH_JSVM_CreateEnv| 创建一个新的JS执行上下文环境,并注册指定的Native函数 |
381| OH_JSVM_DestroyEnv| 销毁一个JS执行上下文环境 |
382| OH_JSVM_OpenEnvScope| 打开一个新的Env scope,Env只能在scope范围内使用 |
383| OH_JSVM_CloseEnvScope| 关闭Env scope |
384| OH_JSVM_OpenHandleScope| 打开一个Handle scope,确保scope范围内的JSVM_Value不被GC回收 |
385| OH_JSVM_CloseHandleScope| 关闭Handle scope |
386
387场景示例:
388创建及销毁JavaScript引擎实例,包含创建及销毁JS执行上下文环境。
389
390```c++
391bool VM_INIT = false;
392
393static JSVM_Value ConsoleInfo(JSVM_Env env, JSVM_CallbackInfo info) {
394    size_t argc = 1;
395    JSVM_Value args[1];
396    char log[256] = "";
397    size_t logLength;
398    OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL);
399
400    OH_JSVM_GetValueStringUtf8(env, args[0], log, 255, &logLength);
401    log[255] = 0;
402    OH_LOG_INFO(LOG_APP, "JSVM API TEST: %{public}s", log);
403    return nullptr;
404}
405
406static JSVM_Value Add(JSVM_Env env, JSVM_CallbackInfo info) {
407    size_t argc = 2;
408    JSVM_Value args[2];
409    OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL);
410    double num1, num2;
411    env, OH_JSVM_GetValueDouble(env, args[0], &num1);
412    OH_JSVM_GetValueDouble(env, args[1], &num2);
413    JSVM_Value sum = nullptr;
414    OH_JSVM_CreateDouble(env, num1 + num2, &sum);
415    return sum;
416}
417
418static napi_value MyJSVMDemo([[maybe_unused]] napi_env _env, [[maybe_unused]] napi_callback_info _info) {
419    std::thread t([]() {
420        if (!VM_INIT) {
421            // JSVM only need init once
422            JSVM_InitOptions initOptions;
423            memset(&initOptions, 0, sizeof(initOptions));
424            OH_JSVM_Init(&initOptions);
425            VM_INIT = true;
426        }
427        // create vm, and open vm scope
428        JSVM_VM vm;
429        JSVM_CreateVMOptions options;
430        memset(&options, 0, sizeof(options));
431        OH_JSVM_CreateVM(&options, &vm);
432
433        JSVM_VMScope vmScope;
434        OH_JSVM_OpenVMScope(vm, &vmScope);
435
436        JSVM_CallbackStruct param[] = {
437            {.data = nullptr, .callback = ConsoleInfo},
438            {.data = nullptr, .callback = Add},
439        };
440        JSVM_PropertyDescriptor descriptor[] = {
441            {"consoleinfo", NULL, &param[0], NULL, NULL, NULL, JSVM_DEFAULT},
442            {"add", NULL, &param[1], NULL, NULL, NULL, JSVM_DEFAULT},
443        };
444        // create env, register native method, and open env scope
445        JSVM_Env env;
446        OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env);
447
448        JSVM_EnvScope envScope;
449        OH_JSVM_OpenEnvScope(env, &envScope);
450
451        // open handle scope
452        JSVM_HandleScope handleScope;
453        OH_JSVM_OpenHandleScope(env, &handleScope);
454
455        std::string sourceCodeStr = "\
456{\
457let value = add(4.96, 5.28);\
458consoleinfo('Result is:' + value);\
459}\
460";
461        // compile js script
462        JSVM_Value sourceCodeValue;
463        OH_JSVM_CreateStringUtf8(env, sourceCodeStr.c_str(), sourceCodeStr.size(), &sourceCodeValue);
464        JSVM_Script script;
465        OH_JSVM_CompileScript(env, sourceCodeValue, nullptr, 0, true, nullptr, &script);
466        JSVM_Value result;
467        // run js script
468        OH_JSVM_RunScript(env, script, &result);
469        JSVM_ValueType type;
470        OH_JSVM_Typeof(env, result, &type);
471        OH_LOG_INFO(LOG_APP, "JSVM API TEST type: %{public}d", type);
472
473        // exit vm and clean memory
474        OH_JSVM_CloseHandleScope(env, handleScope);
475
476        OH_JSVM_CloseEnvScope(env, envScope);
477        OH_JSVM_DestroyEnv(env);
478
479        OH_JSVM_CloseVMScope(vm, vmScope);
480        OH_JSVM_DestroyVM(vm);
481    });
482
483    t.detach();
484
485    return nullptr;
486}
487```
488
489### 使用 JSVM-API 接口编译及执行 JS 代码
490
491#### 场景介绍
492
493编译及执行JS代码。
494
495#### 接口说明
496| 接口                              | 功能说明                                                                               |
497| ------------------------------- | ---------------------------------------------------------------------------------- |
498| OH_JSVM_CompileScript           | 编译JavaScript代码并返回绑定到当前环境的编译脚本                                                      |
499| OH_JSVM_CompileScriptWithOrigin | 编译JavaScript代码并返回绑定到当前环境的编译脚本,同时传入包括 sourceMapUrl 和源文件名在内的源代码信息,用于处理 source map 信息 |
500| OH_JSVM_CompileScriptWithOptions | 通用的编译接口,通过传入 option 数组完成前面的 compile 接口全部功能,同时支持后续选项扩展 |
501| OH_JSVM_CreateCodeCache         | 为编译脚本创建code cache                                                                  |
502| OH_JSVM_RunScript               | 执行编译脚本                                                                             |
503
504场景示例:
505编译及执行JS代码(创建vm,注册function,执行js,销毁vm)。
506
507```c++
508#include <cstring>
509#include <fstream>
510#include <string>
511#include <vector>
512
513// 依赖libjsvm.so
514#include "ark_runtime/jsvm.h"
515
516using namespace std;
517
518static JSVM_Value Hello(JSVM_Env env, JSVM_CallbackInfo info) {
519    JSVM_Value output;
520    void* data = nullptr;
521    OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, nullptr, &data);
522    OH_JSVM_CreateStringUtf8(env, (char*)data, strlen((char*)data), &output);
523    return output;
524}
525
526static JSVM_CallbackStruct hello_cb = { Hello, (void*)"Hello" };
527
528static string srcGlobal = R"JS(
529const concat = (...args) => args.reduce((a, b) => a + b);
530)JS";
531
532static void RunScriptWithOption(JSVM_Env env, string& src,
533								uint8_t** dataPtr = nullptr,
534								size_t* lengthPtr = nullptr) {
535    JSVM_HandleScope handleScope;
536    OH_JSVM_OpenHandleScope(env, &handleScope);
537
538    JSVM_Value jsSrc;
539    OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);
540
541    uint8_t* data = dataPtr ? *dataPtr : nullptr;
542    auto compilMode = data ? JSVM_COMPILE_MODE_CONSUME_CODE_CACHE :  JSVM_COMPILE_MODE_DEFAULT;
543    size_t length = lengthPtr ? *lengthPtr : 0;
544    JSVM_Script script;
545    // 编译js代码
546	JSVM_ScriptOrigin origin {
547	    // 以包名 helloworld 为例, 假如存在对应的 sourcemap, source map 的的路径可以是 /data/app/el2/100/base/com.example.helloworld/files/index.js.map
548	    .sourceMapUrl = "/data/app/el2/100/base/com.example.helloworld/files/index.js.map",
549	    // 源文件名字
550	    .resourceName = "index.js",
551	    // scirpt 在源文件中的起始行列号
552	    .resourceLineOffset = 0,
553	    .resourceColumnOffset = 0,
554	};
555	JSVM_CompileOptions option[3];
556	option[0] = {
557		.id = JSVM_COMPILE_MODE,
558		.content = { .num = compilMode }
559	};
560	JSVM_CodeCache codeCache = {
561		.cache = data,
562		.length = length
563	};
564	option[1] = {
565		.id = JSVM_COMPILE_CODE_CACHE,
566		.content = { .ptr = &codeCache }
567	};
568	// JSVM_COMPILE_ENABLE_SOURCE_MAP 选项默认值为 false,若为 true 那么对应的 sourceMapUrl 必须不为空
569	option[2] = {
570		.id = JSVM_COMPILE_ENABLE_SOURCE_MAP,
571		.content = { .boolean = true }
572	};
573	OH_JSVM_CompileScriptWithOptions(env, jsSrc, 3, option, &script);
574
575    JSVM_Value result;
576    // 执行js代码
577    OH_JSVM_RunScript(env, script, &result);
578
579    char resultStr[128];
580    size_t size;
581    OH_JSVM_GetValueStringUtf8(env, result, resultStr, 128, &size);
582    printf("%s\n", resultStr);
583    if (dataPtr && lengthPtr && *dataPtr == nullptr) {
584        // 将js源码编译出的脚本保存到cache,可以避免重复编译,带来性能提升
585        OH_JSVM_CreateCodeCache(env, script, (const uint8_t**)dataPtr, lengthPtr);
586        printf("Code cache created with length = %ld\n", *lengthPtr);
587    }
588
589    OH_JSVM_CloseHandleScope(env, handleScope);
590}
591
592static void RunScript(JSVM_Env env, string& src,
593                       bool withOrigin = false,
594                       uint8_t** dataPtr = nullptr,
595                       size_t* lengthPtr = nullptr) {
596    JSVM_HandleScope handleScope;
597    OH_JSVM_OpenHandleScope(env, &handleScope);
598
599    JSVM_Value jsSrc;
600    OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);
601
602    uint8_t* data = dataPtr ? *dataPtr : nullptr;
603    size_t length = lengthPtr ? *lengthPtr : 0;
604    bool cacheRejected = true;
605    JSVM_Script script;
606    // 编译js代码
607    if (withOrigin) {
608	    JSVM_ScriptOrigin origin {
609	        // 以包名 helloworld 为例, 假如存在对应的 sourcemap, source map 的的路径可以是 /data/app/el2/100/base/com.example.helloworld/files/index.js.map
610		    .sourceMapUrl = "/data/app/el2/100/base/com.example.helloworld/files/index.js.map",
611		    // 源文件名字
612		    .resourceName = "index.js",
613		    // scirpt 在源文件中的起始行列号
614		    .resourceLineOffset = 0,
615		    .resourceColumnOffset = 0,
616	    };
617		OH_JSVM_CompileScriptWithOrigin(env, jsSrc, data, length, true, &cacheRejected, &origin, &script);
618    } else {
619	    OH_JSVM_CompileScript(env, jsSrc, data, length, true, &cacheRejected, &script);
620    }
621    printf("Code cache is %s\n", cacheRejected ? "rejected" : "used");
622
623    JSVM_Value result;
624    // 执行js代码
625    OH_JSVM_RunScript(env, script, &result);
626
627    char resultStr[128];
628    size_t size;
629    OH_JSVM_GetValueStringUtf8(env, result, resultStr, 128, &size);
630    printf("%s\n", resultStr);
631    if (dataPtr && lengthPtr && *dataPtr == nullptr) {
632        // 将js源码编译出的脚本保存到cache,可以避免重复编译,带来性能提升
633        OH_JSVM_CreateCodeCache(env, script, (const uint8_t**)dataPtr, lengthPtr);
634        printf("Code cache created with length = %ld\n", *lengthPtr);
635    }
636
637    OH_JSVM_CloseHandleScope(env, handleScope);
638}
639
640static void CreateSnapshot() {
641    JSVM_VM vm;
642    JSVM_CreateVMOptions options;
643    memset(&options, 0, sizeof(options));
644    options.isForSnapshotting = true;
645    OH_JSVM_CreateVM(&options, &vm);
646    JSVM_VMScope vmScope;
647    OH_JSVM_OpenVMScope(vm, &vmScope);
648
649    JSVM_Env env;
650    // 将native函数注册成js可调用的方法,hello_cb中记录该native方法的指针和参数等信息
651    JSVM_PropertyDescriptor descriptors[] = {
652        { "hello", NULL, &hello_cb, NULL, NULL, NULL, JSVM_DEFAULT }
653    };
654    OH_JSVM_CreateEnv(vm, 1, descriptors, &env);
655
656    JSVM_EnvScope envScope;
657    OH_JSVM_OpenEnvScope(env, &envScope);
658    // 执行js源码src,src中可以包含任何js语法。也可以调用已注册的native方法。
659    string src = srcGlobal + "concat(hello(), ', ', 'World from CreateSnapshot!');";
660    RunScript(env, src, true);
661
662    // 创建snapshot,将当前的env保存到字符串,可以在某个时机通过该字符串还原出env,避免重复定义该env中的属性,带来性能提升。
663    const char* blobData = nullptr;
664    size_t blobSize = 0;
665    JSVM_Env envs[1] = { env };
666    OH_JSVM_CreateSnapshot(vm, 1, envs, &blobData, &blobSize);
667    printf("Snapshot blob size = %ld\n", blobSize);
668
669    // 如果将snapshot保存到文件中,需要考虑应用中的文件读写权限
670    ofstream file("/data/storage/el2/base/files/blob.bin", ios::out | ios::binary | ios::trunc);
671    file.write(blobData, blobSize);
672    file.close();
673
674    OH_JSVM_CloseEnvScope(env, envScope);
675    OH_JSVM_DestroyEnv(env);
676    OH_JSVM_CloseVMScope(vm, vmScope);
677    OH_JSVM_DestroyVM(vm);
678}
679
680void RunWithoutSnapshot(uint8_t** dataPtr, size_t* lengthPtr) {
681    // 创建虚拟机实例
682    JSVM_VM vm;
683    OH_JSVM_CreateVM(nullptr, &vm);
684    JSVM_VMScope vmScope;
685    OH_JSVM_OpenVMScope(vm, &vmScope);
686
687    JSVM_Env env;
688    // 将native函数注册成js可调用的方法,hello_cb中记录该native方法的指针和参数等信息
689    JSVM_PropertyDescriptor descriptors[] = {
690        { "hello", NULL, &hello_cb, NULL, NULL, NULL, JSVM_DEFAULT }
691    };
692    OH_JSVM_CreateEnv(vm, 1, descriptors, &env);
693    JSVM_EnvScope envScope;
694    OH_JSVM_OpenEnvScope(env, &envScope);
695    // 执行js源码src,src中可以包含任何js语法。也可以调用已注册的native方法。
696    auto src = srcGlobal + "concat(hello(), ', ', 'World', ' from RunWithoutSnapshot!')";
697    // 其中使用新增接口,可以覆盖原有 Compile 系列接口的功能且具有拓展性
698    RunScriptWithOption(env, src, dataPtr, lengthPtr);
699
700    OH_JSVM_CloseEnvScope(env, envScope);
701    OH_JSVM_DestroyEnv(env);
702    OH_JSVM_CloseVMScope(vm, vmScope);
703    OH_JSVM_DestroyVM(vm);
704}
705
706void RunWithSnapshot(uint8_t **dataPtr, size_t *lengthPtr) {
707    // The lifetime of blobData must not be shorter than that of the vm.
708    // 如果从文件中读取snapshot,需要考虑应用中的文件读写权限
709    vector<char> blobData;
710    ifstream file("/data/storage/el2/base/files/blob.bin", ios::in | ios::binary | ios::ate);
711    size_t blobSize = file.tellg();
712    blobData.resize(blobSize);
713    file.seekg(0, ios::beg);
714    file.read(blobData.data(), blobSize);
715    file.close();
716
717    // 创建虚拟机实例
718    JSVM_VM vm;
719    JSVM_CreateVMOptions options;
720    memset(&options, 0, sizeof(options));
721    options.snapshotBlobData = blobData.data();
722    options.snapshotBlobSize = blobSize;
723    OH_JSVM_CreateVM(&options, &vm);
724    JSVM_VMScope vmScope;
725    OH_JSVM_OpenVMScope(vm, &vmScope);
726
727    // 从快照中创建env
728    JSVM_Env env;
729    OH_JSVM_CreateEnvFromSnapshot(vm, 0, &env);
730    JSVM_EnvScope envScope;
731    OH_JSVM_OpenEnvScope(env, &envScope);
732
733    // 执行js脚本,因为快照记录的env中定义了hello(),所以无需重新定义。dataPtr中如果保存了编译后的js脚本,就能直接执行js脚本,避免从源码重复编译。
734    string src = "concat(hello(), ', ', 'World', ' from RunWithSnapshot!')";
735    RunScript(env, src, true, dataPtr, lengthPtr);
736
737    OH_JSVM_CloseEnvScope(env, envScope);
738    OH_JSVM_DestroyEnv(env);
739    OH_JSVM_CloseVMScope(vm, vmScope);
740    OH_JSVM_DestroyVM(vm);
741}
742
743void PrintVmInfo() {
744    JSVM_VMInfo vmInfo;
745    OH_JSVM_GetVMInfo(&vmInfo);
746    printf("apiVersion: %d\n", vmInfo.apiVersion);
747    printf("engine: %s\n", vmInfo.engine);
748    printf("version: %s\n", vmInfo.version);
749    printf("cachedDataVersionTag: 0x%x\n", vmInfo.cachedDataVersionTag);
750}
751
752static intptr_t externals[] = {
753    (intptr_t)&hello_cb,
754    0,
755};
756
757int main(int argc, char *argv[]) {
758    if (argc <= 1) {
759        printf("Usage: %s gen-snapshot|use-snapshot|no-snapshot\n", argv[0]);
760        return 0;
761    }
762
763    JSVM_InitOptions initOptions;
764    memset(&initOptions, 0, sizeof(initOptions));
765    initOptions.externalReferences = externals;
766    // 初始化引擎,一个进程中只能初始化一次
767    OH_JSVM_Init(&initOptions);
768    PrintVmInfo();
769
770    if (argv[1] == string("gen-snapshot")) {
771        CreateSnapshot();
772        return 0;
773    }
774
775    // snapshot可以记录下某个时间的js执行环境,可以跨进程通过snapshot快速还原出js执行上下文环境,前提是保证snapshot数据的生命周期。
776    const auto useSnapshot = argv[1] == string("use-snapshot");
777    const auto run = useSnapshot ? RunWithSnapshot : RunWithoutSnapshot;
778    uint8_t* data = nullptr;
779    size_t length = 0;
780    run(&data, &length);
781    run(&data, &length);
782    delete[] data;
783
784    return 0;
785}
786```
787
788### 使用 JSVM-API WebAssembly 接口编译 wasm module
789
790#### 场景介绍
791
792JSVM-API WebAssembly 接口提供了 wasm 字节码编译、wasm 函数优化、wasm cache 序列化和反序列化的能力。
793
794#### 接口说明
795
796| 接口                          | 功能说明                                                                                 |
797| --------------------------- | ------------------------------------------------------------------------------------ |
798| OH_JSVM_CompileWasmModule   | 将 wasm 字节码同步编译为 wasm module。如果提供了 cache 参数,先尝试将 cache 反序列为 wasm module,反序列化失败时再执行编译。 |
799| OH_JSVM_CompileWasmFunction | 将 wasm module 中指定编号的函数编译为优化后的机器码,目前只使能了最高的优化等级,函数编号的合法性由接口调用者保证。                     |
800| OH_JSVM_IsWasmModuleObject  | 判断传入的值是否是一个 wasm module。                                                             |
801| OH_JSVM_CreateWasmCache     | 将 wasm module 中的机器码序列化为 wasm cache,如果 wasm module 不包含机器码,则会序列化失败。                    |
802| OH_JSVM_ReleaseCache        | 释放由 JSVM 接口生成的 cache。传入的 cacheType 和 cacheData 必须匹配,否则会产生未定义行为。                      |
803
804#### 场景示例
805
806详见[使用 JSVM-API WebAssembly 接口](use-jsvm-about-wasm.md)。
807
808### 异常处理
809
810#### 场景介绍
811
812获取、抛出、清理JS异常
813
814#### 接口说明
815| 接口 | 功能说明 |
816| -------- | -------- |
817| OH_JSVM_Throw| 抛出一个JS值 |
818| OH_JSVM_ThrowTypeError| 抛出一个JS TypeError |
819| OH_JSVM_ThrowRangeError| 抛出一个JS RangeError |
820| OH_JSVM_IsError| 判断JS值是否为JS异常 |
821| OH_JSVM_CreateError| 创建一个JS异常 |
822| OH_JSVM_CreateTypeError| 创建一个JS TypeError并返回 |
823| OH_JSVM_CreateRangeError| 创建一个JS RangeError并返回 |
824| OH_JSVM_ThrowError| 抛出一个JS异常 |
825| OH_JSVM_GetAndClearLastException| 清理并返回最后一个JS异常 |
826| OH_JSVM_IsExceptionPending| 判断当前是否有异常 |
827| OH_JSVM_GetLastErrorInfo| 获取最后一个异常的信息 |
828| OH_JSVM_ThrowSyntaxError| 抛出一个JS SyntaxError |
829| OH_JSVM_CreateSyntaxError| 创建一个JS SyntaxError并返回 |
830
831场景示例:
832以TypeError为例。创建,判断,并抛出JS TypeError。
833
834```c++
835JSVM_Value code = nullptr;
836JSVM_Value message = nullptr;
837OH_JSVM_CreateStringUtf8(env, "500", JSVM_AUTO_LENGTH, &code);
838OH_JSVM_CreateStringUtf8(env, "type error 500", JSVM_AUTO_LENGTH, &message);
839JSVM_Value error = nullptr;
840OH_JSVM_CreateTypeError(env, code, message, &error);
841bool isError = false;
842OH_JSVM_IsError(env, error, &isError);
843OH_JSVM_ThrowTypeError(env, nullptr, "type error1");
844```
845
846使用OH_JSVM_GetAndClearLastException后将异常信息以字符串形式打印
847
848```c++
849if (status != JSVM_OK) // 当执行失败出现异常时
850{
851    bool isPending = false;
852    if (JSVM_OK == OH_JSVM_IsExceptionPending((env), &isPending) && isPending)
853    {
854        JSVM_Value error;
855        if (JSVM_OK == OH_JSVM_GetAndClearLastException((env), &error))
856        {
857            // 获取异常堆栈
858            JSVM_Value stack;
859            OH_JSVM_GetNamedProperty((env), error, "stack", &stack);
860
861            JSVM_Value message;
862            OH_JSVM_GetNamedProperty((env), error, "message", &message);
863
864            char stackstr[256];
865            OH_JSVM_GetValueStringUtf8(env, stack, stackstr, 256, nullptr);
866            OH_LOG_INFO(LOG_APP, "JSVM error stack: %{public}s", stackstr);
867
868            char messagestr[256];
869            OH_JSVM_GetValueStringUtf8(env, message, messagestr, 256, nullptr);
870            OH_LOG_INFO(LOG_APP, "JSVM error message: %{public}s", messagestr);
871        }
872    }
873}
874```
875
876### 对象生命周期管理
877
878在调用JSVM-API接口时,底层VM堆中的对象可能会作为JSVM_Values返回句柄。这些句柄必须在Native方法退出或主动释放掉前,使其关联的对象处于“活动”状态,防止被引擎回收掉。
879
880当对象句柄被返回时,它们与一个“scope”相关联。默认作用域的生命周期与本机方法调用的生命周期相关联,这些句柄及关联的对象将在Native方法的生命周期内保持活动状态。
881
882然而,在许多情况下,句柄必须保持有效的时间范围并不与Native方法的生命周期相同。下面将介绍可用于更改句柄的生命周期的JSVM-API方法。
883
884#### 对象生命周期管理接口说明
885| 接口 | 功能说明 |
886| -------- | -------- |
887| OH_JSVM_OpenHandleScope| 打开一个新的scope,在关闭该scope之前创建的对象在scope范围内不会被GC回收 |
888| OH_JSVM_CloseHandleScope| 关闭一个scope,在此scope范围内创建的对象在关闭scope后可以被GC回收|
889| OH_JSVM_OpenEscapableHandleScope| 打开一个新的scope逃逸handle scope,在关闭该scope之前创建的对象与父作用域有相同的生命周期 |
890| OH_JSVM_CloseEscapableHandleScope| 关闭一个scope,在此scope范围外创建的对象不受父作用域保护 |
891| OH_JSVM_EscapeHandle| 将 JavaScript 对象的句柄提升到外部作用域,确保在外部作用域中可以持续地使用该对象 |
892| OH_JSVM_CreateReference| 以指定的引用计数为JavaScript对象创建一个新的引用,该引用将指向传入的对象,引用允许在不同的上下文中使用和共享对象,并且可以有效地跟踪对象的生命周期 |
893| OH_JSVM_DeleteReference| 释放由 OH_JSVM_CreateReference 创建的引用,确保对象在不再被使用时能够被正确地释放和回收,避免内存泄漏 |
894| OH_JSVM_ReferenceRef| 增加由OH_JSVM_CreateReference 创建的引用的引用计数,以确保对象在有引用时不会被提前释放 |
895| OH_JSVM_ReferenceUnref| 减少由OH_JSVM_CreateReference 创建的引用的引用计数,以确保没有任何引用指向该对象时能正确地释放和回收 |
896| OH_JSVM_GetReferenceValue| 返回由 OH_JSVM_CreateReference 创建的引用的对象 |
897| OH_JSVM_RetainScript | 持久化保存一个 JSVM_Script, 使其能够跨过当前 scope 使用 |
898| OH_JSVM_ReleaseScript | 释放持久化保存过的 JSVM_Script,释放之后 JSVM_Script 不再可用,应当置为空 |
899
900场景示例:
901通过handlescope保护在scope范围内创建的对象在该范围内不被回收。
902
903```c++
904JSVM_HandleScope scope;
905OH_JSVM_OpenHandleScope(env, &scope);
906JSVM_Value obj = nullptr;
907OH_JSVM_CreateObject(env, &obj);
908OH_JSVM_CloseHandleScope(env, scope);
909```
910
911通过escapable handlescope保护在scope范围内创建的对象在父作用域范围内不被回收
912
913```c++
914JSVM_EscapableHandleScope scope;
915JSVM_CALL(env, OH_JSVM_OpenEscapableHandleScope(env, &scope));
916JSVM_Value output = NULL;
917JSVM_Value escapee = NULL;
918JSVM_CALL(env, OH_JSVM_CreateObject(env, &output));
919JSVM_CALL(env, OH_JSVM_EscapeHandle(env, scope, output, &escapee));
920JSVM_CALL(env, OH_JSVM_CloseEscapableHandleScope(env, scope));
921return escapee;
922```
923
924通过CreateReference创建对象引用和释放
925
926```c++
927JSVM_Value obj = nullptr;
928OH_JSVM_CreateObject(env, &obj);
929// 创建引用
930JSVM_Ref reference;
931OH_JSVM_CreateReference(env, obj, 1, &reference);
932
933// 使用引用
934JSVM_Value result;
935OH_JSVM_GetReferenceValue(env, reference, &result);
936
937// 释放引用
938OH_JSVM_DeleteReference(env, reference);
939```
940
941通过 RetainScript 持久化保存 JSVM_Script 并使用
942
943```c++
944JSVM_HandleScope scope;
945OH_JSVM_OpenHandleScope(env, &scope);
946JSVM_Script script;
947JSVM_Value jsSrc;
948std::string src(R"JS(
949let a = 37;
950a = a * 9;
951)JS");
952OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);
953OH_JSVM_CompileScriptWithOptions(env, jsSrc, 0, nullptr, &script);
954OH_JSVM_RetainScript(env, script);
955OH_JSVM_CloseHandleScope(env, scope);
956
957// 使用JSVM_Script
958OH_JSVM_OpenHandleScope(env, &scope);
959JSVM_Value result;
960OH_JSVM_RunScript(env, script, &result);
961
962// 释放JSVM_Script,并置空
963OH_JSVM_ReleaseScript(env, script);
964script = nullptr;
965OH_JSVM_CloseHandleScope(env, scope);
966```
967
968### 创建JS对象类型和基本类型
969
970#### 场景介绍
971
972创建JS对象类型和基本类型
973
974#### 接口说明
975| 接口 | 功能说明 |
976| -------- | -------- |
977|OH_JSVM_CreateArray | 创建一个新的 JavaScript 数组对象 |
978|OH_JSVM_CreateArrayWithLength | 创建一个指定长度的 JavaScript 数组对象 |
979|OH_JSVM_CreateArraybuffer | 创建一个指定大小的 ArrayBuffer 对象 |
980|OH_JSVM_CreateDate | 创建了一个表示给定毫秒数的 Date 对象 |
981|OH_JSVM_CreateExternal | 创建一个包装了外部指针的 JavaScript 对象 |
982|OH_JSVM_CreateObject | 创建一个默认的JavaScript Object对象 |
983|OH_JSVM_CreateSymbol | 根据给定的描述符创建一个 Symbol 对象 |
984|OH_JSVM_SymbolFor | 在全局注册表中搜索具有给定描述的现有Symbol,如果该Symbol已经存在,它将被返回,否则将在注册表中创建一个新Symbol |
985|OH_JSVM_CreateTypedarray | 在现有的 ArrayBuffer 上创建一个 JavaScript TypedArray 对象,TypedArray 对象在底层数据缓冲区上提供类似数组的视图,其中每个元素都具有相同的底层二进制标量数据类型 |
986|OH_JSVM_CreateDataview | 在现有的 ArrayBuffer 上创建一个 JavaScript DataView 对象,DataView 对象在底层数据缓冲区上提供类似数组的视图 |
987|OH_JSVM_CreateInt32 | 根据 Int32_t 类型对象创建 JavaScript number 对象 |
988|OH_JSVM_CreateUint32 | 根据 Uint32_t 类型对象创建 JavaScript number 对象 |
989|OH_JSVM_CreateInt64 | 根据 Int64_t 类型对象创建 JavaScript number 对象 |
990|OH_JSVM_CreateDouble | 根据 Double 类型对象创建 JavaScript number 对象 |
991|OH_JSVM_CreateBigintInt64 | 根据 Int64 类型对象创建 JavaScript Bigint 对象 |
992|OH_JSVM_CreateBigintUint64 | 根据 Uint64 类型对象创建 JavaScript Bigint 对象 |
993|OH_JSVM_CreateBigintWords | 根据给定的 Uint64_t 数组创建一个 JavaScript BigInt 对象 |
994|OH_JSVM_CreateStringLatin1 | 根据 Latin-1 编码的字符串创建一个 JavaScript string 对象 |
995|OH_JSVM_CreateStringUtf16 | 根据 Utf16 编码的字符串创建一个 JavaScript string 对象 |
996|OH_JSVM_CreateStringUtf8 | 根据 Utf8 编码的字符串创建一个 JavaScript string 对象 |
997|OH_JSVM_CreateMap | 创建一个新的 JavaScript Map对象 |
998|OH_JSVM_CreateRegExp | 根据输入的字符串创建一个JavaScript 正则对象 |
999|OH_JSVM_CreateSet | 创建一个新的 JavaScript Set对象 |
1000
1001场景示例:
1002创建指定长度的数组。
1003
1004```c++
1005size_t arrayLength = 2;
1006JSVM_Value arr;
1007
1008OH_JSVM_CreateArrayWithLength(env, arrayLength, &arr);
1009for (uint32_t i = 0; i < arrayLength; i++)
1010{
1011    JSVM_Value element;
1012    OH_JSVM_CreateUint32(env, i * 2, &element);
1013    OH_JSVM_SetElement(env, arr, i, element);
1014}
1015```
1016
1017创建typedarray,以Int32Array为例:
1018
1019```c++
1020JSVM_Value arrayBuffer = nullptr;
1021void *arrayBufferPtr = nullptr;
1022size_t arrayBufferSize = 16;
1023size_t typedArrayLength = 4;
1024OH_JSVM_CreateArraybuffer(env, arrayBufferSize, &arrayBufferPtr, &arrayBuffer);
1025
1026void *tmpArrayBufferPtr = nullptr;
1027size_t arrayBufferLength = 0;
1028OH_JSVM_GetArraybufferInfo(env, arrayBuffer, &tmpArrayBufferPtr, &arrayBufferLength);
1029
1030JSVM_Value result;
1031OH_JSVM_CreateTypedarray(env, JSVM_TypedarrayType::JSVM_INT32_ARRAY, typedArrayLength, arrayBuffer, 0, &result);
1032return result;
1033```
1034
1035创建number和string:
1036
1037```c++
1038const char *testStringStr = "test";
1039JSVM_Value testString = nullptr;
1040OH_JSVM_CreateStringUtf8(env, testStringStr, strlen(testStringStr), &testString);
1041
1042JSVM_Value testNumber1 = nullptr;
1043JSVM_Value testNumber2 = nullptr;
1044OH_JSVM_CreateDouble(env, 10.1, &testNumber1);
1045OH_JSVM_CreateInt32(env, 10, &testNumber2);
1046```
1047
1048创建Map:
1049
1050```c++
1051JSVM_Value value = nullptr;
1052OH_JSVM_CreateMap(env, &value);
1053```
1054
1055创建RegExp:
1056
1057```c++
1058JSVM_Value value = nullptr;
1059const char testStr[] = "ab+c";
1060OH_JSVM_CreateStringUtf8(env, testStr, strlen(testStr), &value);
1061JSVM_Value result = nullptr;
1062OH_JSVM_CreateRegExp(env, value, JSVM_RegExpFlags::JSVM_REGEXP_GLOBAL, &result);
1063```
1064
1065创建Set:
1066
1067```c++
1068JSVM_Value value;
1069OH_JSVM_CreateSet(env, &value);
1070```
1071
1072### 从JS类型获取C类型&获取JS类型信息
1073
1074#### 场景介绍
1075
1076从JS类型获取C类型&获取JS类型信息。
1077
1078#### 接口说明
1079| 接口 | 功能说明 |
1080| -------- | -------- |
1081|OH_JSVM_GetArrayLength | 返回 Array 对象的长度 |
1082|OH_JSVM_GetArraybufferInfo | 检索 ArrayBuffer 的底层数据缓冲区及其长度 |
1083|OH_JSVM_GetPrototype | 获取给定 JavaScript 对象的原型 |
1084|OH_JSVM_GetTypedarrayInfo | 获取 TypedArray(类型化数组)对象的信息 |
1085|OH_JSVM_GetDataviewInfo | 获取 Dataview 对象的信息 |
1086|OH_JSVM_GetDateValue | 获取给定 JavaScript Date 的时间值的 Double 基础类型值 |
1087|OH_JSVM_GetValueBool | 获取给定 JavaScript Boolean 的 C 布尔基础类型值 |
1088|OH_JSVM_GetValueDouble | 获取给定 JavaScript number 的 Double 基础类型值 |
1089|OH_JSVM_GetValueBigintInt64 | 获取给定 JavaScript BigInt 的 Int64_t 基础类型值 |
1090|OH_JSVM_GetValueBigintUint64 | 获取给定 JavaScript BigInt 的 Uint64_t 基础类型值 |
1091|OH_JSVM_GetValueBigintWords | 获取给定 JavaScript BigInt 对象的底层数据,即 BigInt 数据的字词表示 |
1092|OH_JSVM_GetValueExternal | 获取先前传递给 OH_JSVM_CreateExternal 的外部数据指针 |
1093|OH_JSVM_GetValueInt32 | 获取给定 JavaScript number 的 Int32 基础类型值 |
1094|OH_JSVM_GetValueInt64 | 获取给定 JavaScript number 的 Int64 基础类型值 |
1095|OH_JSVM_GetValueStringLatin1 | 获取给定 JavaScript string 对象的 Latin1 编码字符串 |
1096|OH_JSVM_GetValueStringUtf8 | 获取给定 JavaScript string 对象的 Utf8 编码字符串 |
1097|OH_JSVM_GetValueStringUtf16 | 获取给定 JavaScript string 对象的 Utf16 编码字符串 |
1098|OH_JSVM_GetValueUint32 | 获取给定 JavaScript number 的 Uint32 基础类型值 |
1099|OH_JSVM_GetBoolean | 返回用于表示给定布尔值的 JavaScript 单例对象 |
1100|OH_JSVM_GetGlobal | 返回当前环境中的全局 global 对象 |
1101|OH_JSVM_GetNull | 返回 JavaScript null 对象 |
1102|OH_JSVM_GetUndefined | 返回 JavaScript Undefined 对象 |
1103
1104场景示例:
1105创建64位的BigInt,并获取64位int值。
1106
1107```c++
1108int64_t testValue = INT64_MAX;
1109JSVM_Value result = nullptr;
1110OH_JSVM_CreateBigintInt64(env, testValue, &result);
1111int64_t resultValue = 0;
1112bool flag = false;
1113OH_JSVM_GetValueBigintInt64(env, result, &resultValue, &flag);
1114```
1115
1116创建一个Int32Array,并获取其长度,byteoffset等信息。
1117
1118```c++
1119JSVM_Value arrayBuffer = nullptr;
1120void *arrayBufferPtr = nullptr;
1121size_t arrayBufferSize = 16;
1122size_t typedArrayLength = 4;
1123OH_JSVM_CreateArraybuffer(env, arrayBufferSize, &arrayBufferPtr, &arrayBuffer);
1124
1125bool isArrayBuffer = false;
1126OH_JSVM_IsArraybuffer(env, arrayBuffer, &isArrayBuffer);
1127
1128JSVM_Value result;
1129OH_JSVM_CreateTypedarray(env, JSVM_TypedarrayType::JSVM_INT32_ARRAY, typedArrayLength, arrayBuffer, 0, &result);
1130
1131bool isTypedArray = false;
1132OH_JSVM_IsTypedarray(env, result, &isTypedArray);
1133
1134
1135JSVM_TypedarrayType type;
1136size_t length = 0;
1137void *data = nullptr;
1138JSVM_Value retArrayBuffer;
1139size_t byteOffset = -1;
1140OH_JSVM_GetTypedarrayInfo(env, result, &type, &length, &data, &retArrayBuffer, &byteOffset);
1141
1142
1143bool retIsArrayBuffer = false;
1144OH_JSVM_IsArraybuffer(env, retArrayBuffer, &retIsArrayBuffer);
1145void *tmpArrayBufferPtr = nullptr;
1146size_t arrayBufferLength = 0;
1147OH_JSVM_GetArraybufferInfo(env, retArrayBuffer, &tmpArrayBufferPtr, &arrayBufferLength);
1148```
1149
1150创建utf8类型的String,并获取C字符串。
1151
1152```c++
1153const char *testStringStr = "testString";
1154JSVM_Value testString = nullptr;
1155OH_JSVM_CreateStringUtf8(env, testStringStr, strlen(testStringStr), &testString);
1156
1157char buffer[128];
1158size_t bufferSize = 128;
1159size_t copied;
1160
1161OH_JSVM_GetValueStringUtf8(env, testString, buffer, bufferSize, &copied);
1162```
1163
1164### JS值操作和抽象操作
1165
1166#### 场景介绍
1167
1168JS值操作和抽象操作。
1169
1170#### 接口说明
1171| 接口 | 功能说明 |
1172| -------- | -------- |
1173|OH_JSVM_CoerceToBool | 将目标值转换为 Boolean 类型对象|
1174|OH_JSVM_CoerceToNumber | 将目标值转换为 Number 类型对象 |
1175|OH_JSVM_CoerceToObject | 将目标值转换为 Object 类型对象 |
1176|OH_JSVM_CoerceToString | 将目标值转换为 String 类型对象 |
1177|OH_JSVM_CoerceToBigInt | 将目标值转换为 BigInt 类型对象 |
1178|OH_JSVM_Typeof | 返回 JavaScript 对象的类型 |
1179|OH_JSVM_Instanceof | 判断一个对象是否是某个构造函数的实例 |
1180|OH_JSVM_IsArray | 判断一个 JavaScript 对象是否为 Array 类型对象|
1181|OH_JSVM_IsArraybuffer | 判断一个 JavaScript 对象是否为 Arraybuffer 类型对象 |
1182|OH_JSVM_IsDate | 判断一个 JavaScript 对象是否为 Date 类型对象 |
1183|OH_JSVM_IsTypedarray | 判断一个 JavaScript 对象是否为 Typedarray 类型对象 |
1184|OH_JSVM_IsDataview | 判断一个 JavaScript 对象是否为 Dataview 类型对象 |
1185|OH_JSVM_IsUndefined | 此API检查传入的值是否为Undefined。这相当于JS中的`value === undefined`。 |
1186|OH_JSVM_IsNull | 此API检查传入的值是否为Null对象。这相当于JS中的`value === null`。 |
1187|OH_JSVM_IsNullOrUndefined | 此API检查传入的值是否为Null或Undefined。这相当于JS中的`value == null`。 |
1188|OH_JSVM_IsBoolean | 此API检查传入的值是否为Boolean。这相当于JS中的`typeof value === 'boolean'`。 |
1189|OH_JSVM_IsNumber | 此API检查传入的值是否为Number。这相当于JS中的`typeof value === 'number'`。 |
1190|OH_JSVM_IsString | 此API检查传入的值是否为String。这相当于JS中的`typeof value === 'string'`。 |
1191|OH_JSVM_IsSymbol | 此API检查传入的值是否为Symbol。这相当于JS中的`typeof value === 'symbol'`。 |
1192|OH_JSVM_IsFunction | 此API检查传入的值是否为Function。这相当于JS中的`typeof value === 'function'`。 |
1193|OH_JSVM_IsObject | 此API检查传入的值是否为Object。 |
1194|OH_JSVM_IsBigInt | 此API检查传入的值是否为BigInt。这相当于JS中的`typeof value === 'bigint'`。 |
1195|OH_JSVM_IsConstructor | 此API检查传入的值是否为构造函数。 |
1196|OH_JSVM_IsMap | 此API检查传入的值是否为Map。 |
1197|OH_JSVM_IsSet | 此API检查传入的值是否为Set。 |
1198|OH_JSVM_IsRegExp | 此API检查传入的值是否为RegExp。 |
1199|OH_JSVM_StrictEquals | 判断两个 JSVM_Value 对象是否严格相等 |
1200|OH_JSVM_Equals | 判断两个 JSVM_Value 对象是否宽松相等 |
1201|OH_JSVM_DetachArraybuffer | 调用 ArrayBuffer 对象的Detach操作 |
1202|OH_JSVM_IsDetachedArraybuffer | 检查给定的 ArrayBuffer 是否已被分离(detached) |
1203
1204场景示例:
1205判断JS值是否为数组类型
1206
1207```c++
1208JSVM_Value array = nullptr;
1209OH_JSVM_CreateArray(env, &array);
1210bool isArray = false;
1211OH_JSVM_IsArray(env, array, &isArray);
1212```
1213
1214将int32类型转换为string类型
1215
1216```c++
1217int32_t num = 123;
1218JSVM_Value intValue;
1219OH_JSVM_CreateInt32(env, num, &intValue);
1220JSVM_Value stringValue;
1221OH_JSVM_CoerceToString(env, intValue, &stringValue);
1222
1223char buffer[128];
1224size_t bufferSize = 128;
1225size_t copied = 0;
1226
1227OH_JSVM_GetValueStringUtf8(env, stringValue, buffer, bufferSize, &copied);
1228// buffer:"123";
1229```
1230
1231将boolean类型转换为bigint类型
1232
1233```c++
1234JSVM_Value boolValue;
1235OH_JSVM_GetBoolean(env, false, &boolValue);
1236JSVM_Value bigIntValue;
1237OH_JSVM_CoerceToBigInt(env, boolValue, &bigIntValue);
1238```
1239
1240判断两个JS值类型是否严格相同:先比较操作数类型,操作数类型不同就是不相等,操作数类型相同时,比较值是否相等,相等才返回true。
1241
1242```c++
1243JSVM_Value value = nullptr;
1244JSVM_Value value1 = nullptr;
1245OH_JSVM_CreateArray(env, &value);
1246
1247OH_JSVM_CreateInt32(env, 10, &value1);
1248bool isArray = true;
1249OH_JSVM_StrictEquals(env, value, value, &isArray);
1250```
1251
1252判断两个JS值类型是否宽松相同:判断两个操作数的类型是否相同,若不相同,且可以转换为相同的数据类型,转换为相同的数据类型后,值做严格相等比较,其他的都返回false。
1253
1254```c++
1255JSVM_HandleScope handleScope;
1256OH_JSVM_OpenHandleScope(env, &handleScope);
1257const char testStr[] = "1";
1258JSVM_Value lhs = nullptr;
1259OH_JSVM_CreateStringUtf8(env, testStr, strlen(testStr), &lhs);
1260JSVM_Value rhs;
1261OH_JSVM_CreateInt32(env, 1, &rhs);
1262bool isEquals = false;
1263OH_JSVM_Equals(env, lhs, rhs, &isEquals); // 这里isEquals的值是true
1264OH_JSVM_CloseHandleScope(env, handleScope);
1265```
1266
1267判断JS值是否为构造函数
1268
1269```c++
1270JSVM_Value SayHello(JSVM_Env env, JSVM_CallbackInfo info)
1271{
1272    return nullptr;
1273}
1274JSVM_Value value = nullptr;
1275JSVM_CallbackStruct param;
1276param.data = nullptr;
1277param.callback = SayHello;
1278OH_JSVM_CreateFunction(env, "func", JSVM_AUTO_LENGTH, &param, &value);
1279bool isConstructor = false;
1280OH_JSVM_IsConstructor(env, value, &isConstructor); // 这里isConstructor的值是true
1281```
1282
1283判断JS值是否为map类型
1284
1285```c++
1286JSVM_Value value = nullptr;
1287OH_JSVM_CreateMap(env, &value);
1288bool isMap = false;
1289OH_JSVM_IsMap(env, value, &isMap); // 这里isMap的值是true
1290```
1291
1292判断JS值是否为Set类型
1293
1294```c++
1295JSVM_Value value;
1296OH_JSVM_CreateSet(env, &value);
1297bool isSet = false;
1298OH_JSVM_IsSet(env, value, &isSet); // 这里isSet的值是true
1299```
1300
1301判断JS值是否为RegExp类型
1302
1303```c++
1304JSVM_Value value = nullptr;
1305const char testStr[] = "ab+c";
1306OH_JSVM_CreateStringUtf8(env, testStr, strlen(testStr), &value);
1307JSVM_Value result = nullptr;
1308OH_JSVM_CreateRegExp(env, value, JSVM_RegExpFlags::JSVM_REGEXP_GLOBAL, &result);
1309bool isRegExp = false;
1310OH_JSVM_IsRegExp(env, result, &isRegExp);
1311```
1312
1313### JS属性操作
1314
1315#### 场景介绍
1316
1317JS对象属性的增删获取和判断
1318
1319#### 接口说明
1320| 接口 | 功能说明 |
1321| -------- | -------- |
1322|OH_JSVM_GetPropertyNames | 获取给定对象的所有可枚举属性名称, 结果变量将存储一个包含所有可枚举属性名称的JavaScript数组。 |
1323|OH_JSVM_GetAllPropertyNames | 获取给定对象的所有可用属性名称, 结果变量将存储一个包含所有可枚举属性名称的JavaScript数组。 |
1324|OH_JSVM_SetProperty | 为给定对象设置一个属性。 |
1325|OH_JSVM_GetProperty | 用给定的属性的名称,检索目标对象的属性。 |
1326|OH_JSVM_HasProperty | 用给定的属性的名称,查询目标对象是否有此属性。 |
1327|OH_JSVM_DeleteProperty | 用给定的属性的名称,删除目标对象属性。 |
1328|OH_JSVM_HasOwnProperty | 检查目标对象是否具有指定的自有属性。 |
1329|OH_JSVM_SetNamedProperty | 用给定的属性的名称为目标对象设置属性,此方法等效于使用从作为 utf8Name 传入的字符串创建的 JSVM_Value 调用 OH_JSVM_SetProperty。 |
1330|OH_JSVM_GetNamedProperty | 用给定的属性的名称,检索目标对象的属性,此方法等效于使用从作为 utf8Name 传入的字符串创建的 JSVM_Value 调用 OH_JSVM_GetProperty。 |
1331|OH_JSVM_HasNamedProperty | 用给定的属性的名称,查询目标对象是否有此属性,此方法等效于使用从作为 utf8Name 传入的字符串创建的 JSVM_Value 调用 OH_JSVM_HasProperty。 |
1332|OH_JSVM_SetElement | 在给定对象的指定索引处设置元素。 |
1333|OH_JSVM_GetElement | 获取给定对象指定索引处的元素。 |
1334|OH_JSVM_HasElement | 若给定对象的指定索引处拥有属性,获取该元素。 |
1335|OH_JSVM_DeleteElement | 尝试删除给定对象的指定索引处的元素。 |
1336|OH_JSVM_DefineProperties |  批量的向给定对象中定义属性。 |
1337|OH_JSVM_ObjectFreeze | 冻结给定的对象,防止向其添加新属性,删除现有属性,防止更改现有属性的可枚举性、可配置性或可写性,并防止更改现有属性的值。 |
1338|OH_JSVM_ObjectSeal | 密封给定的对象。这可以防止向其添加新属性,以及将所有现有属性标记为不可配置。 |
1339|OH_JSVM_ObjectSetPrototypeOf | 为给定对象设置一个原型。 |
1340|OH_JSVM_ObjectGetPrototypeOf | 获取给定JavaScript对象的原型。 |
1341
1342场景示例:
1343JS对象属性的增删获取和判断
1344
1345```c++
1346// 创建一个空对象
1347JSVM_Value myObject = nullptr;
1348OH_JSVM_CreateObject(env, &myObject);
1349
1350// 设置属性
1351const char *testNameStr = "John Doe";
1352JSVM_Value propValue = nullptr;
1353JSVM_Value key;
1354OH_JSVM_CreateStringUtf8(env, "name", JSVM_AUTO_LENGTH, &key);
1355OH_JSVM_CreateStringUtf8(env, testNameStr, strlen(testNameStr), &propValue);
1356OH_JSVM_SetProperty(env, myObject, key, propValue);
1357
1358// 获取属性
1359JSVM_Value propResult = nullptr;
1360OH_JSVM_GetProperty(env, myObject, key, &propResult);
1361
1362// 检查属性是否存在
1363bool hasProperty = false;
1364OH_JSVM_HasNamedProperty(env, myObject, "name", &hasProperty);
1365    // 属性存在,做相应处理...
1366    if (hasProperty)
1367    {
1368        // 获取对象的所有属性名
1369        JSVM_Value propNames = nullptr;
1370        OH_JSVM_GetPropertyNames(env, myObject, &propNames);
1371
1372        bool isArray = false;
1373        OH_JSVM_IsArray(env, propNames, &isArray);
1374
1375        uint32_t arrayLength = 0;
1376        OH_JSVM_GetArrayLength(env, propNames, &arrayLength);
1377        // 遍历属性元素
1378        for (uint32_t i = 0; i < arrayLength; i++)
1379        {
1380            bool hasElement = false;
1381            OH_JSVM_HasElement(env, propNames, i, &hasElement);
1382
1383            JSVM_Value propName = nullptr;
1384            OH_JSVM_GetElement(env, propNames, i, &propName);
1385
1386            bool hasProp = false;
1387            OH_JSVM_HasProperty(env, myObject, propName, &hasProp);
1388
1389            JSVM_Value propValue = nullptr;
1390            OH_JSVM_GetProperty(env, myObject, propName, &propValue);
1391        }
1392    }
1393
1394// 删除属性
1395OH_JSVM_DeleteProperty(env, myObject, key, &hasProperty);
1396
1397// 设置对象原型
1398JSVM_Value value;
1399OH_JSVM_CreateSet(env, &value);
1400OH_JSVM_ObjectSetPrototypeOf(env, myObject, value);
1401
1402// 获取对象原型
1403JSVM_Value proto;
1404OH_JSVM_ObjectGetPrototypeOf(env, myObject, &proto);
1405```
1406
1407### JS函数操作
1408
1409#### 场景介绍
1410
1411JS函数操作。
1412
1413#### 接口说明
1414| 接口 | 功能说明 |
1415| -------- | -------- |
1416|OH_JSVM_CallFunction | 在C/C++侧调用JS方法 |
1417|OH_JSVM_CreateFunction | 用于创建JavaScript函数,用于从JavaScript环境中调用C/C++代码中的函数 |
1418|OH_JSVM_GetCbInfo | 从给定的callback info中获取有关调用的详细信息,如参数和this指针 |
1419|OH_JSVM_GetNewTarget | 获取构造函数调用的new.target |
1420|OH_JSVM_NewInstance | 通过给定的构造函数,构建一个实例 |
1421|OH_JSVM_CreateFunctionWithScript | 根据传入的函数体和函数参数列表,创建一个新的 JavaScript Function对象 |
1422
1423场景示例:
1424创建JavaScript函数操作
1425
1426```c++
1427JSVM_Value SayHello(JSVM_Env env, JSVM_CallbackInfo info)
1428{
1429    printf("Hello\n");
1430    JSVM_Value ret;
1431    OH_JSVM_CreateInt32(env, 2, &ret);
1432    return ret;
1433}
1434
1435static JSVM_Value JsvmCreateFunction(JSVM_Env env, JSVM_CallbackInfo info)
1436{
1437    JSVM_CallbackStruct param;
1438    param.data = nullptr;
1439    param.callback = SayHello;
1440
1441    JSVM_Value funcValue = nullptr;
1442    JSVM_Status status = OH_JSVM_CreateFunction(env, "func", JSVM_AUTO_LENGTH, &param, &funcValue);
1443    return funcValue;
1444}
1445```
1446
1447在C/C++侧获取并调用JS方法
1448
1449```c++
1450static JSVM_Value CallFunction(JSVM_Env env, JSVM_CallbackInfo info)
1451{
1452    size_t argc = 1;
1453    JSVM_Value args[1];
1454    JSVM_CALL(env, OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL));
1455
1456    JSVM_ASSERT(env, argc >= 1, "Wrong number of arguments");
1457
1458    JSVM_ValueType valuetype;
1459    JSVM_CALL(env, OH_JSVM_Typeof(env, args[0], &valuetype));
1460    JSVM_ASSERT(env, valuetype == JSVM_ValueType::JSVM_FUNCTION, "Wrong type of argment. Expects a string.");
1461
1462    JSVM_Value global;
1463    JSVM_CALL(env, OH_JSVM_GetGlobal(env, &global));
1464
1465    JSVM_Value ret;
1466    JSVM_CALL(env, OH_JSVM_CallFunction(env, global, args[0], 0, nullptr, &ret));
1467    return ret;
1468}
1469```
1470
1471创建Function:
1472
1473```c++
1474JSVM_Value script;
1475OH_JSVM_CreateStringUtf8(env, "return a + b;", JSVM_AUTO_LENGTH, &script);
1476JSVM_Value param1;
1477JSVM_Value param2;
1478OH_JSVM_CreateStringUtf8(env, "a", JSVM_AUTO_LENGTH, &param1);
1479OH_JSVM_CreateStringUtf8(env, "b", JSVM_AUTO_LENGTH, &param2);
1480JSVM_Value argus[] = {param1, param2};
1481JSVM_Value func;
1482OH_JSVM_CreateFunctionWithScript(env, "add", JSVM_AUTO_LENGTH, 2, argus, script, &func);
1483```
1484
1485### 对象绑定操作
1486
1487#### 场景介绍
1488
1489对象绑定操作。
1490
1491#### 接口说明
1492| 接口 | 功能说明 |
1493| -------- | -------- |
1494|OH_JSVM_DefineClass| 用于在JavaScript中定义一个类,并与对应的C类进行封装和交互。它提供了创建类的构造函数、定义属性和方法的能力,以及在C和JavaScript之间进行数据交互的支持。 |
1495|OH_JSVM_Wrap| 在 JavaScript 对象中封装原生实例。稍后可以使用 OH_JSVM_Unwrap() 检索原生实例。 |
1496|OH_JSVM_Unwrap | 使用 OH_JSVM_Wrap() 检索先前封装在 JavaScript 对象中的原生实例。 |
1497|OH_JSVM_RemoveWrap | 检索先前封装在 JavaScript 对象中的原生实例并移除封装。 |
1498|OH_JSVM_TypeTagObject | 将 type_tag 指针的值与 JavaScript 对象或外部对象相关联。 |
1499|OH_JSVM_CheckObjectTypeTag | 检查给定的类型标签是否与对象上的类型标签匹配。 |
1500|OH_JSVM_AddFinalizer | 为对象添加 JSVM_Finalize 回调,以便在 JavaScript 对象被垃圾回收时调用来释放原生对象。 |
1501|OH_JSVM_DefineClassWithPropertyHandler | 定义一个具有给定类名、构造函数、属性和回调处理程序的JavaScript类,并作为函数回调进行调用。属性操作包括getter、setter、deleter、enumerator等。 |
1502
1503场景示例:
1504对象绑定操作。
1505
1506```c++
1507static JSVM_Value AssertEqual(JSVM_Env env, JSVM_CallbackInfo info)
1508{
1509    size_t argc = 2;
1510    JSVM_Value args[2];
1511    JSVM_CALL(env, OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL));
1512
1513    bool isStrictEquals = false;
1514    OH_JSVM_StrictEquals(env, args[0], args[1], &isStrictEquals);
1515    return nullptr;
1516}
1517
1518static napi_value TestWrap(napi_env env1, napi_callback_info info)
1519{
1520    OH_LOG_ERROR(LOG_APP, "testWrap start");
1521    JSVM_InitOptions init_options;
1522    memset(&init_options, 0, sizeof(init_options));
1523    init_options.externalReferences = externals;
1524    if (aa == 0) {
1525        OH_JSVM_Init(&init_options);
1526        aa++;
1527    }
1528    JSVM_VM vm;
1529    JSVM_CreateVMOptions options;
1530    memset(&options, 0, sizeof(options));
1531    OH_JSVM_CreateVM(&options, &vm);
1532    JSVM_VMScope vm_scope;
1533    OH_JSVM_OpenVMScope(vm, &vm_scope);
1534    JSVM_Env env;
1535    JSVM_CallbackStruct param[1];
1536    param[0].data = nullptr;
1537    param[0].callback = AssertEqual;
1538    JSVM_PropertyDescriptor descriptor[] = {
1539        {"assertEqual", NULL, &param[0], NULL, NULL, NULL, JSVM_DEFAULT},
1540    };
1541    OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env);
1542    JSVM_EnvScope envScope;
1543    OH_JSVM_OpenEnvScope(env, &envScope);
1544    JSVM_HandleScope handlescope;
1545    OH_JSVM_OpenHandleScope(env, &handlescope);
1546    JSVM_Value testClass = nullptr;
1547    JSVM_CallbackStruct param1;
1548    param1.data = nullptr;
1549    param1.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
1550        JSVM_Value thisVar = nullptr;
1551        OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr);
1552
1553        return thisVar;
1554    };
1555    OH_JSVM_DefineClass(env, "TestClass", JSVM_AUTO_LENGTH, &param1, 0, nullptr, &testClass);
1556
1557    JSVM_Value instanceValue = nullptr;
1558    OH_JSVM_NewInstance(env, testClass, 0, nullptr, &instanceValue);
1559
1560    const char *testStr = "test";
1561    OH_JSVM_Wrap(
1562        env, instanceValue, (void *)testStr, [](JSVM_Env env, void *data, void *hint) {}, nullptr, nullptr);
1563    const char *tmpTestStr = nullptr;
1564    OH_JSVM_Unwrap(env, instanceValue, (void **)&tmpTestStr);
1565    const char *tmpTestStr1 = nullptr;
1566    OH_JSVM_RemoveWrap(env, instanceValue, (void **)&tmpTestStr1);
1567    OH_JSVM_Unwrap(env, instanceValue, (void **)&tmpTestStr1);
1568    OH_JSVM_CloseHandleScope(env, handlescope);
1569    OH_JSVM_CloseEnvScope(env, envScope);
1570    OH_JSVM_DestroyEnv(env);
1571    OH_JSVM_CloseVMScope(vm, vm_scope);
1572    OH_JSVM_DestroyVM(vm);
1573    OH_LOG_ERROR(LOG_APP, "testWrap pass");
1574    return nullptr;
1575}
1576```
1577
1578场景示例:
1579对象绑定及监听拦截属性操作。
1580
1581```c++
1582static int aa = 0;
1583static JSVM_Value hello(JSVM_Env env, JSVM_CallbackInfo info) {
1584    JSVM_Value output;
1585    void *data = nullptr;
1586    OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, nullptr, &data);
1587    OH_JSVM_CreateStringUtf8(env, (char *)data, strlen((char *)data), &output);
1588    return output;
1589}
1590
1591static JSVM_CallbackStruct hello_cb = {hello, (void *)"Hello"};
1592static intptr_t externals[] = {
1593    (intptr_t)&hello_cb,
1594    0,
1595};
1596
1597static void test1() { OH_LOG_INFO(LOG_APP, "test1 called"); }
1598
1599struct Test {
1600    void *ptr1;
1601    void *ptr2;
1602};
1603
1604static JSVM_Value assertEqual(JSVM_Env env, JSVM_CallbackInfo info) {
1605    size_t argc = 2;
1606    JSVM_Value args[2];
1607    JSVM_CALL(env, OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL));
1608
1609    bool isStrictEquals = false;
1610    OH_JSVM_StrictEquals(env, args[0], args[1], &isStrictEquals);
1611    return nullptr;
1612}
1613
1614static JSVM_Value GetPropertyCbInfo(JSVM_Env env, JSVM_Value name, JSVM_Value thisArg, JSVM_Value data) {
1615    // 该回调是由对象上的获取请求触发的
1616    char strValue[100];
1617    size_t size;
1618    OH_JSVM_GetValueStringUtf8(env, name, strValue, 300, &size);
1619    JSVM_Value newResult = nullptr;
1620    char newStr[] = "new return value hahaha from name listening";
1621    OH_JSVM_CreateStringUtf8(env, newStr, strlen(newStr), &newResult);
1622    int signBit = 0;
1623    size_t wordCount = 2;
1624    uint64_t wordsOut[2] = {0ULL, 0ULL};
1625    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1626    if (status == JSVM_OK) {
1627        OH_LOG_INFO(LOG_APP, "GetPropertyCbInfo wordCount is %{public}zu", wordCount);
1628        auto test = reinterpret_cast<Test *>(wordsOut);
1629        typedef void (*callTest1)();
1630        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1631        callTe();
1632    }
1633    return nullptr;
1634}
1635
1636static JSVM_Value SetPropertyCbInfo(JSVM_Env env, JSVM_Value name, JSVM_Value property, JSVM_Value thisArg, JSVM_Value data) {
1637    // 该回调是由对象上的设置请求触发的
1638    char strValue[100];
1639    size_t size;
1640    OH_JSVM_GetValueStringUtf8(env, name, strValue, 300, &size);
1641    JSVM_Value newResult = nullptr;
1642    char newStr[] = "new return value hahaha from name listening";
1643    OH_JSVM_CreateStringUtf8(env, newStr, strlen(newStr), &newResult);
1644    int signBit = 0;
1645    size_t wordCount = 2;
1646    uint64_t wordsOut[2] = {0ULL, 0ULL};
1647    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1648    if (status == JSVM_OK) {
1649        OH_LOG_INFO(LOG_APP, "SetPropertyCbInfo wordCount is %{public}zu", wordCount);
1650        auto test = reinterpret_cast<Test *>(wordsOut);
1651        typedef void (*callTest1)();
1652        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1653        callTe();
1654    }
1655    return nullptr;
1656}
1657
1658static JSVM_Value DeleterPropertyCbInfo(JSVM_Env env, JSVM_Value name, JSVM_Value thisArg, JSVM_Value data) {
1659    // 该回调是由对象上的删除请求触发的
1660    char strValue[100];
1661    size_t size;
1662    OH_JSVM_GetValueStringUtf8(env, name, strValue, 300, &size);
1663    JSVM_Value newResult = nullptr;
1664    bool returnValue = false;
1665    OH_JSVM_GetBoolean(env, returnValue, &newResult);
1666    int signBit = 0;
1667    size_t wordCount = 2;
1668    uint64_t wordsOut[2] = {0ULL, 0ULL};
1669    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1670    if (status == JSVM_OK) {
1671        OH_LOG_INFO(LOG_APP, "DeleterPropertyCbInfo wordCount is %{public}zu", wordCount);
1672        auto test = reinterpret_cast<Test *>(wordsOut);
1673        typedef void (*callTest1)();
1674        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1675        callTe();
1676    }
1677    return nullptr;
1678}
1679
1680static JSVM_Value EnumeratorPropertyCbInfo(JSVM_Env env, JSVM_Value thisArg, JSVM_Value data) {
1681    // 该回调是由获取对象上的所有属性请求触发的
1682    JSVM_Value testArray = nullptr;
1683    OH_JSVM_CreateArrayWithLength(env, 2, &testArray);
1684    JSVM_Value name1 = nullptr;
1685    char newStr1[] = "hahaha";
1686    OH_JSVM_CreateStringUtf8(env, newStr1, strlen(newStr1), &name1);
1687    JSVM_Value name2 = nullptr;
1688    char newStr2[] = "heheheh";
1689    OH_JSVM_CreateStringUtf8(env, newStr2, strlen(newStr2), &name2);
1690
1691    OH_JSVM_SetElement(env, testArray, 0, name1);
1692    OH_JSVM_SetElement(env, testArray, 1, name2);
1693    int signBit = 0;
1694    size_t wordCount = 2;
1695    uint64_t wordsOut[2] = {0ULL, 0ULL};
1696    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1697    if (status == JSVM_OK) {
1698        OH_LOG_INFO(LOG_APP, "EnumeratorPropertyCbInfo wordCount is %{public}zu", wordCount);
1699        auto test = reinterpret_cast<Test *>(wordsOut);
1700        typedef void (*callTest1)();
1701        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1702        callTe();
1703    }
1704    return nullptr;
1705}
1706
1707static JSVM_Value IndexedPropertyGet(JSVM_Env env, JSVM_Value index, JSVM_Value thisArg, JSVM_Value data) {
1708    // 该回调是由获取实例对象的索引属性触发的
1709    uint32_t value;
1710    OH_JSVM_GetValueUint32(env, index, &value);
1711
1712    JSVM_Value newResult = nullptr;
1713    char newStr[] = "new return value hahaha from index listening";
1714    OH_JSVM_CreateStringUtf8(env, newStr, strlen(newStr), &newResult);
1715    int signBit = 0;
1716    size_t wordCount = 2;
1717    uint64_t wordsOut[2] = {0ULL, 0ULL};
1718    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1719    if (status == JSVM_OK) {
1720        OH_LOG_INFO(LOG_APP, "IndexedPropertyGet wordCount is %{public}zu", wordCount);
1721        auto test = reinterpret_cast<Test *>(wordsOut);
1722        typedef void (*callTest1)();
1723        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1724        callTe();
1725    }
1726    return nullptr;
1727}
1728
1729static JSVM_Value IndexedPropertySet(JSVM_Env env, JSVM_Value index, JSVM_Value property, JSVM_Value thisArg, JSVM_Value data) {
1730    // 该回调是由设置实例对象的索引属性触发的
1731    uint32_t value;
1732    OH_JSVM_GetValueUint32(env, index, &value);
1733    char str[100];
1734    size_t size;
1735    OH_JSVM_GetValueStringUtf8(env, property, str, 100, &size);
1736    JSVM_Value newResult = nullptr;
1737    char newStr[] = "new return value hahaha from name listening";
1738    OH_JSVM_CreateStringUtf8(env, newStr, strlen(newStr), &newResult);
1739    int signBit = 0;
1740    size_t wordCount = 2;
1741    uint64_t wordsOut[2] = {0ULL, 0ULL};
1742    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1743    if (status == JSVM_OK) {
1744        OH_LOG_INFO(LOG_APP, "IndexedPropertySet wordCount is %{public}zu", wordCount);
1745        auto test = reinterpret_cast<Test *>(wordsOut);
1746        typedef void (*callTest1)();
1747        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1748        callTe();
1749    }
1750    return nullptr;
1751}
1752
1753static JSVM_Value IndexedPropertyDeleter(JSVM_Env env, JSVM_Value index, JSVM_Value thisArg, JSVM_Value data) {
1754    // 该回调是由删除实例对象的索引属性触发的
1755    uint32_t value;
1756    OH_JSVM_GetValueUint32(env, index, &value);
1757    JSVM_Value newResult = nullptr;
1758    bool returnValue = false;
1759    OH_JSVM_GetBoolean(env, returnValue, &newResult);
1760    int signBit = 0;
1761    size_t wordCount = 2;
1762    uint64_t wordsOut[2] = {0ULL, 0ULL};
1763    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1764    if (status == JSVM_OK) {
1765        OH_LOG_INFO(LOG_APP, "IndexedPropertyDeleter wordCount is %{public}zu", wordCount);
1766        auto test = reinterpret_cast<Test *>(wordsOut);
1767        typedef void (*callTest1)();
1768        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1769        callTe();
1770    }
1771    return nullptr;
1772}
1773
1774static JSVM_Value IndexedPropertyEnumerator(JSVM_Env env, JSVM_Value thisArg, JSVM_Value data) {
1775    // 该回调是由获取对象上的所有索引属性请求触发的
1776    JSVM_Value testArray = nullptr;
1777    OH_JSVM_CreateArrayWithLength(env, 2, &testArray);
1778    JSVM_Value index1 = nullptr;
1779    OH_JSVM_CreateUint32(env, 1, &index1);
1780    JSVM_Value index2 = nullptr;
1781    OH_JSVM_CreateUint32(env, 2, &index2);
1782    OH_JSVM_SetElement(env, testArray, 0, index1);
1783    OH_JSVM_SetElement(env, testArray, 1, index2);
1784    int signBit = 0;
1785    size_t wordCount = 2;
1786    uint64_t wordsOut[2] = {0ULL, 0ULL};
1787    JSVM_Status status = OH_JSVM_GetValueBigintWords(env, data, &signBit, &wordCount, wordsOut);
1788    if (status == JSVM_OK) {
1789        OH_LOG_INFO(LOG_APP, "IndexedPropertyDeleter wordCount is %{public}zu", wordCount);
1790        auto test = reinterpret_cast<Test *>(wordsOut);
1791        typedef void (*callTest1)();
1792        callTest1 callTe = reinterpret_cast<callTest1>(test->ptr1);
1793        callTe();
1794    }
1795    return nullptr;
1796}
1797
1798static napi_value TestDefineClassWithProperty(napi_env env1, napi_callback_info info) {
1799    OH_LOG_ERROR(LOG_APP, "TestDefineClassWithProperty start");
1800    JSVM_InitOptions init_options;
1801    memset(&init_options, 0, sizeof(init_options));
1802    init_options.externalReferences = externals;
1803    if (aa == 0) {
1804        OH_JSVM_Init(&init_options);
1805        aa++;
1806    }
1807    JSVM_VM vm;
1808    JSVM_CreateVMOptions options;
1809    memset(&options, 0, sizeof(options));
1810    OH_JSVM_CreateVM(&options, &vm);
1811    JSVM_VMScope vm_scope;
1812    OH_JSVM_OpenVMScope(vm, &vm_scope);
1813    JSVM_Env env;
1814    JSVM_CallbackStruct param[1];
1815    param[0].data = nullptr;
1816    param[0].callback = assertEqual;
1817    JSVM_PropertyDescriptor descriptor[] = {
1818        {"assertEqual", NULL, &param[0], NULL, NULL, NULL, JSVM_DEFAULT},
1819    };
1820    OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env);
1821    JSVM_EnvScope envScope;
1822    OH_JSVM_OpenEnvScope(env, &envScope);
1823    JSVM_HandleScope handlescope;
1824    OH_JSVM_OpenHandleScope(env, &handlescope);
1825
1826
1827    JSVM_CallbackStruct param1;
1828    param1.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
1829        JSVM_Value thisVar = nullptr;
1830        OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr);
1831        return thisVar;
1832    };
1833    param1.data = nullptr;
1834
1835    JSVM_Value res = nullptr;
1836    Test *test = new Test();
1837    test->ptr1 = (void *)test1;
1838    test->ptr2 = (void *)test1;
1839    OH_LOG_INFO(LOG_APP, "OH_JSVM_CreateBigintWords 111 word count %{public}d",
1840                sizeof(*test) / sizeof(uint64_t));
1841    JSVM_Status status = OH_JSVM_CreateBigintWords(env, 1, 2, reinterpret_cast<const uint64_t *>(test), &res);
1842
1843    // 初始化propertyCfg
1844    JSVM_PropertyHandlerConfigurationStruct propertyCfg;
1845    propertyCfg.genericNamedPropertyGetterCallback = GetPropertyCbInfo;
1846    propertyCfg.genericNamedPropertySetterCallback = SetPropertyCbInfo;
1847    propertyCfg.genericNamedPropertyDeleterCallback = DeleterPropertyCbInfo;
1848    propertyCfg.genericNamedPropertyEnumeratorCallback = EnumeratorPropertyCbInfo;
1849    propertyCfg.genericIndexedPropertyGetterCallback = IndexedPropertyGet;
1850    propertyCfg.genericIndexedPropertySetterCallback = IndexedPropertySet;
1851    propertyCfg.genericIndexedPropertyDeleterCallback = IndexedPropertyDeleter;
1852    propertyCfg.genericIndexedPropertyEnumeratorCallback = IndexedPropertyEnumerator;
1853    propertyCfg.namedPropertyData = res;
1854    propertyCfg.indexedPropertyData = res;
1855
1856    JSVM_CallbackStruct callbackStruct;
1857    callbackStruct.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
1858        OH_LOG_INFO(LOG_APP, "call as a function called");
1859        JSVM_Value thisVar = nullptr;
1860        void *innerData;
1861        size_t argc = 1;
1862        JSVM_Value args[1];
1863        OH_JSVM_GetCbInfo(env, info, &argc, args, &thisVar, &innerData);
1864        OH_LOG_INFO(LOG_APP, "function call as function result is %{public}s", reinterpret_cast<char *>(innerData));
1865        uint32_t ret = 0;
1866        OH_JSVM_GetValueUint32(env, args[0], &ret);
1867        const char testStr[] = "hello world 111111";
1868        JSVM_Value setvalueName = nullptr;
1869        JSVM_CALL(env, OH_JSVM_CreateStringUtf8(env, testStr, strlen(testStr), &setvalueName));
1870        return setvalueName;
1871    };
1872    char data[100] = "1111 hello world";
1873    callbackStruct.data = data;
1874    JSVM_Value testWrapClass = nullptr;
1875
1876    // 将属性的访问监听注册在propertyCfg中
1877    OH_JSVM_DefineClassWithPropertyHandler(env, "TestWrapClass", NAPI_AUTO_LENGTH, &param1, 0, nullptr, &propertyCfg,
1878                                           &callbackStruct, &testWrapClass);
1879    JSVM_Value instanceValue = nullptr;
1880    OH_JSVM_NewInstance(env, testWrapClass, 0, nullptr, &instanceValue);
1881    const char testStr[] = "hello world";
1882    JSVM_Value setvalueName = nullptr;
1883    OH_JSVM_CreateStringUtf8(env, testStr, strlen(testStr), &setvalueName);
1884
1885    // 1. 名称属性回调
1886    // 设置属性
1887    OH_JSVM_SetNamedProperty(env, instanceValue, "str11", setvalueName);
1888    OH_JSVM_SetNamedProperty(env, instanceValue, "str123", setvalueName);
1889
1890    // 获取属性
1891    JSVM_Value valueName = nullptr;
1892    OH_JSVM_GetNamedProperty(env, instanceValue, "str11", &valueName);
1893    char str[100];
1894    size_t size;
1895    OH_JSVM_GetValueStringUtf8(env, valueName, str, 100, &size);
1896
1897    // 获取所有属性的名称
1898    JSVM_Value allPropertyNames = nullptr;
1899    OH_JSVM_GetAllPropertyNames(env, instanceValue, JSVM_KEY_OWN_ONLY,
1900                                static_cast<JSVM_KeyFilter>(JSVM_KEY_ENUMERABLE | JSVM_KEY_SKIP_SYMBOLS),
1901                                JSVM_KEY_NUMBERS_TO_STRINGS, &allPropertyNames);
1902    uint32_t nameSize = 0;
1903    OH_JSVM_GetArrayLength(env, allPropertyNames, &nameSize);
1904    JSVM_Value propertyName = nullptr;
1905    for (uint32_t i = 0; i < nameSize; ++i) {
1906        OH_JSVM_GetElement(env, allPropertyNames, i, &propertyName);
1907        char str[100];
1908        size_t size;
1909        OH_JSVM_GetValueStringUtf8(env, propertyName, str, 100, &size);
1910    }
1911
1912    // 删除属性
1913    bool result = false;
1914    propertyName = nullptr;
1915    char propertyChar[] = "str11";
1916    OH_JSVM_CreateStringUtf8(env, propertyChar, strlen(propertyChar), &propertyName);
1917    OH_JSVM_DeleteProperty(env, instanceValue, propertyName, &result);
1918
1919    // 2. 索引属性回调
1920    // 设置属性
1921    JSVM_Value jsIndex = nullptr;
1922    uint32_t index = 0;
1923    OH_JSVM_CreateUint32(env, index, &jsIndex);
1924    OH_JSVM_SetProperty(env, instanceValue, jsIndex, setvalueName);
1925    JSVM_Value jsIndex1 = nullptr;
1926    index = 1;
1927    OH_JSVM_CreateUint32(env, index, &jsIndex1);
1928    OH_JSVM_SetProperty(env, instanceValue, jsIndex1, setvalueName);
1929
1930    // 获取属性
1931    JSVM_Value valueName1 = nullptr;
1932    OH_JSVM_GetProperty(env, instanceValue, jsIndex, &valueName1);
1933    char str1[100];
1934    size_t size1;
1935    OH_JSVM_GetValueStringUtf8(env, valueName1, str1, 100, &size1);
1936
1937    // 获取所有属性的名称
1938    JSVM_Value allPropertyNames1 = nullptr;
1939    OH_JSVM_GetAllPropertyNames(env, instanceValue, JSVM_KEY_OWN_ONLY,
1940                                static_cast<JSVM_KeyFilter>(JSVM_KEY_ENUMERABLE | JSVM_KEY_SKIP_SYMBOLS),
1941                                JSVM_KEY_NUMBERS_TO_STRINGS, &allPropertyNames1);
1942    uint32_t nameSize1 = 0;
1943    OH_JSVM_GetArrayLength(env, allPropertyNames1, &nameSize);
1944    JSVM_Value propertyName1 = nullptr;
1945    for (uint32_t i = 0; i < nameSize1; ++i) {
1946        OH_JSVM_GetElement(env, allPropertyNames1, i, &propertyName1);
1947        char str[100];
1948        size_t size;
1949        OH_JSVM_GetValueStringUtf8(env, propertyName1, str, 100, &size);
1950    }
1951
1952    // 删除属性
1953    bool result1 = false;
1954    OH_JSVM_DeleteProperty(env, instanceValue, jsIndex, &result1);
1955
1956    // 3. 作为函数的回调
1957    JSVM_Value gloablObj = nullptr;
1958    OH_JSVM_GetGlobal(env, &gloablObj);
1959    OH_JSVM_SetNamedProperty(env, gloablObj, "myTestInstance", instanceValue);
1960    OH_LOG_INFO(LOG_APP, "set property on global object");
1961    std::string innerSourcecodestr = R"(
1962    {
1963        let res = myTestInstance(12);
1964    })";
1965    JSVM_Value innerSourcecodevalue;
1966    OH_JSVM_CreateStringUtf8(env, innerSourcecodestr.c_str(), innerSourcecodestr.size(), &innerSourcecodevalue);
1967    JSVM_Script innerscript;
1968    OH_JSVM_CompileScript(env, innerSourcecodevalue, nullptr, 0, true, nullptr, &innerscript);
1969    JSVM_Value innerResult;
1970    OH_JSVM_RunScript(env, innerscript, &innerResult);
1971
1972    OH_JSVM_CloseHandleScope(env, handlescope);
1973    OH_JSVM_CloseEnvScope(env, envScope);
1974    OH_JSVM_DestroyEnv(env);
1975    OH_JSVM_CloseVMScope(vm, vm_scope);
1976    OH_JSVM_DestroyVM(vm);
1977    OH_LOG_ERROR(LOG_APP, "TestDefineClassWithProperty pass");
1978    return nullptr;
1979}
1980```
1981
1982### 版本管理
1983
1984#### 场景介绍
1985
1986获取当前版本信息。
1987
1988#### 接口说明
1989| 接口 | 功能说明 |
1990| -------- | -------- |
1991|OH_JSVM_GetVersion| 返回JSVM运行时支持的最高JSVM API版本 |
1992|OH_JSVM_GetVMInfo| 返回虚拟机的信息 |
1993
1994场景示例:
1995获取当前版本信息。
1996
1997```c++
1998JSVM_VMInfo result;
1999OH_JSVM_GetVMInfo(&result);
2000uint32_t versionId = 0;
2001OH_JSVM_GetVersion(env, &versionId);
2002```
2003
2004### 内存管理
2005
2006#### 场景介绍
2007
2008内存管理
2009
2010#### 接口说明
2011| 接口                                          | 功能说明                                                                                                   |
2012| ------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
2013| OH_JSVM_AdjustExternalMemory                | 将因JavaScript对象而保持活跃的外部分配的内存大小及时通知给底层虚拟机,虚拟机后续触发GC时,就会综合内外内存状态来判断是否进行全局GC。即增大外部内存分配,则会增大触发全局GC的概率;反之减少。 |
2014| OH_JSVM_MemoryPressureNotification          | 通知虚拟机系统内存压力层级,并有选择地触发垃圾回收。                                                                             |
2015| OH_JSVM_AllocateArrayBufferBackingStoreData | 申请一块 BackingStore 内存 |
2016| OH_JSVM_FreeArrayBufferBackingStoreData | 释放 BackingStore 内存 |
2017| OH_JSVM_CreateArrayBufferFromBackingStoreData | 基于申请的 BackingStore 内存创建 array buffer |
2018
2019> BackingStore 的使用属于高危操作,需要使用者自身保证内存的正确使用,请参考下方的正确示例,谨慎使用。
2020
2021场景示例:
2022内存管理。
2023
2024```c++
2025// 分别在调用OH_JSVM_AdjustExternalMemory前后来查看底层虚拟机视角下外部分配的内存大小
2026int64_t result;
2027OH_JSVM_AdjustExternalMemory(env, 0, &result); // 假设外部分配内存的变化不变
2028OH_LOG_INFO(LOG_APP, "Before AdjustExternalMemory: %{public}lld\n", result); // 得到调整前的数值
2029// 调整外部分配的内存大小通知给底层虚拟机(此示例假设内存使用量增加)
2030int64_t memoryIncrease = 1024 * 1024; // 增加 1 MB
2031OH_JSVM_AdjustExternalMemory(env, memoryIncrease, &result);
2032OH_LOG_INFO(LOG_APP, "After AdjustExternalMemory: %{public}lld\n", result); // 得到调整后的数值
2033```
2034```c++
2035// 打开一个Handle scope,在scope范围内申请大量内存来测试函数功能;
2036// 分别在“完成申请后”、“关闭scope后”和“调用OH_JSVM_MemoryPressureNotification后”三个节点查看内存状态
2037JSVM_HandleScope tmpscope;
2038OH_JSVM_OpenHandleScope(env, &tmpscope);
2039for (int i = 0; i < 1000000; ++i) {
2040    JSVM_Value obj;
2041    OH_JSVM_CreateObject(env, &obj);
2042}
2043JSVM_HeapStatistics mem;
2044OH_JSVM_GetHeapStatistics(vm, &mem); // 获取虚拟机堆的统计数据
2045OH_LOG_INFO(LOG_APP, "%{public}zu\n", mem.usedHeapSize); // 申请完成后,内存处于最大状态
2046OH_JSVM_CloseHandleScope(env, tmpscope); // 关闭Handle scope
2047
2048OH_JSVM_GetHeapStatistics(vm, &mem);
2049OH_LOG_INFO(LOG_APP, "%{public}zu\n", mem.usedHeapSize); // 关闭scope后,GC并没有立即回收
2050
2051// 通知虚拟机系统内存压力层级,并有选择地触发垃圾回收
2052OH_JSVM_MemoryPressureNotification(env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL); // 假设内存压力处于临界状态
2053
2054OH_JSVM_GetHeapStatistics(vm, &mem);
2055OH_LOG_INFO(LOG_APP, "%{public}zu\n", mem.usedHeapSize); // 触发垃圾回收后
2056```
2057
2058BackingStore 正确使用示例
2059``` c++
2060void *backingStore;
2061JSVM_Value arrayBuffer;
2062
2063// 申请一块大小为 100 字节的 BackingStore 内存
2064OH_JSVM_AllocateArrayBufferBackingStoreData(100, JSVM_ZERO_INITIALIZED, &backingStore);
2065
2066// 在之前申请的 BackingStore 上创建一个 ArrayBuffer,位置为距离 BackingStore 起始地址加 30 字节处,大小为 20 字节
2067OH_JSVM_CreateArrayBufferFromBackingStoreData(env, backingStore, 100, 30, 20, &arrayBuffer);
2068
2069// 在 JS 中使用创建的 ArrayBuffer
2070JSVM_Value js_global;
2071JSVM_Value name;
2072OH_JSVM_GetGlobal(jsvm_env, &js_global);
2073OH_JSVM_CreateStringUtf8(jsvm_env, "buffer", JSVM_AUTO_LENGTH, &name);
2074OH_JSVM_SetProperty(env, js_global, name, arrayBuffer);
2075
2076JSVM_Script script;
2077JSVM_Value scriptString;
2078JSVM_Value result;
2079const char *src = R"JS(
2080function writeBuffer(data) {
2081  let view = new Uint8Array(data);
2082  // Write some values to the ArrayBuffer
2083  for (let i = 0; i < view.length; i++) {
2084    view[i] = i % 256;
2085  }
2086}
2087writeBuffer(buffer)
2088)JS";
2089OH_JSVM_CreateStringUtf8(env, src, JSVM_AUTO_LENGTH, &scriptString);
2090OH_JSVM_CompileScriptWithOptions(env, scriptString, 0, nullptr, &script);
2091OH_JSVM_RunScript(env, script, &result);
2092
2093// 检查 ArrayBuffer 的内容
2094uint8_t *array = static_cast<uint8_t*>(backingStore);
2095for (auto i = 0; i < 100; ++i) {
2096  if (array[i] != i % 25 % 256) {
2097    return false;
2098  }
2099}
2100
2101// 释放 array buffer. 注意对于这种方式创建的 ArrayBuffer, 在释放对应的 BackingStore 之前,
2102// 务必使用 OH_JSVM_DetachArraybuffer 将所有使用当前的 BackingStore 创建的 ArrayBuffer 释放
2103// 否则可能产生不可预测的内存问题,请谨慎使用
2104OH_JSVM_DetachArraybuffer(env, arrayBuffer);
2105
2106// 释放申请的 backing store 内存
2107OH_JSVM_FreeArrayBufferBackingStoreData(backingStore);
2108```
2109### Promise操作
2110
2111#### 场景介绍
2112
2113Promise相关操作。
2114
2115#### 接口说明
2116| 接口 | 功能说明 |
2117| -------- | -------- |
2118|OH_JSVM_CreatePromise| 创建一个延迟对象和一个JavaScript promise |
2119|OH_JSVM_ResolveDeferred| 通过与之关联的延迟对象来解析JavaScript promise |
2120|OH_JSVM_RejectDeferred| 通过与之关联的延迟对象来拒绝JavaScript Promise |
2121|OH_JSVM_IsPromise| 查询Promise是否为原生Promise对象 |
2122
2123场景示例:
2124Promise相关操作。
2125
2126```c++
2127JSVM_Deferred deferred;
2128JSVM_Value promise;
2129OH_JSVM_CreatePromise(env, &deferred, &promise);
2130
2131// 模拟异步操作
2132int result = 42;
2133bool success = true;
2134if (success)
2135{
2136    // 解析Promise,并传递结果
2137    JSVM_Value value;
2138    OH_JSVM_CreateInt32(env, result, &value);
2139    OH_JSVM_ResolveDeferred(env, deferred, value);
2140} else {
2141    // 拒绝Promise,并传递错误信息
2142    JSVM_Value code = nullptr;
2143    JSVM_Value message = nullptr;
2144    OH_JSVM_CreateStringUtf8(env, "600", JSVM_AUTO_LENGTH, &code);
2145    OH_JSVM_CreateStringUtf8(env, "Async operation failed", JSVM_AUTO_LENGTH, &message);
2146    JSVM_Value error = nullptr;
2147    OH_JSVM_CreateError(env, code, message, &error);
2148    OH_JSVM_RejectDeferred(env, deferred, error);
2149}
2150```
2151
2152### JSON操作
2153
2154#### 场景介绍
2155
2156JSON操作。
2157
2158#### 接口说明
2159
2160| 接口 | 功能说明 |
2161| -------- | -------- |
2162|OH_JSVM_JsonParse| 解析JSON字符串,并返回成功解析的值 |
2163|OH_JSVM_JsonStringify| 将对象字符串化,并返回成功转换后的字符串 |
2164
2165场景示例:
2166解析JSON操作。
2167
2168```c++
2169std::string sourcecodestr = "{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}" ;
2170JSVM_Value jsonString;
2171OH_JSVM_CreateStringUtf8(env, sourcecodestr.c_str(), sourcecodestr.size(), &jsonString)
2172JSVM_Value result;
2173OH_JSVM_JsonParse(env, jsonString, &result);
2174```
2175
2176### 创建和使用虚拟机的启动快照
2177
2178#### 场景介绍
2179
2180创建和使用虚拟机的启动快照
2181
2182#### 接口说明
2183| 接口 | 功能说明 |
2184| -------- | -------- |
2185|OH_JSVM_CreateSnapshot| 用于创建虚拟机的启动快照 |
2186|OH_JSVM_CreateEnvFromSnapshot| 基于启动快照创建jsvm环境 |
2187
2188场景示例:
2189[创建和使用虚拟机的启动快照。](use-jsvm-create-snapshot.md)
2190
2191### 检查传入的值是否可调用
2192
2193#### 场景介绍
2194
2195检查传入的值是否可调用
2196
2197#### 接口说明
2198| 接口 | 功能说明 |
2199| -------- | -------- |
2200|OH_JSVM_IsCallable| 检查传入的值是否可调用 |
2201
2202场景示例:
2203检查传入的值是否可调用
2204
2205```c++
2206static JSVM_Value NapiIsCallable(JSVM_Env env, JSVM_CallbackInfo info) {
2207    JSVM_Value value, rst;
2208    size_t argc = 1;
2209    bool isCallable = false;
2210    JSVM_CALL(env, OH_JSVM_GetCbInfo(env, info, &argc, &value, NULL, NULL));
2211    JSVM_CALL(env, OH_JSVM_IsCallable(env, value, &isCallable));
2212    OH_JSVM_GetBoolean(env, isCallable, &rst);
2213    return rst;
2214}
2215
2216static napi_value MyJSVMDemo([[maybe_unused]] napi_env _env, [[maybe_unused]] napi_callback_info _info) {
2217    std::thread t([]() {
2218        // create vm, and open vm scope
2219        JSVM_VM vm;
2220        JSVM_CreateVMOptions options;
2221        memset(&options, 0, sizeof(options));
2222        OH_JSVM_CreateVM(&options, &vm);
2223        JSVM_VMScope vmScope;
2224        OH_JSVM_OpenVMScope(vm, &vmScope);
2225        JSVM_CallbackStruct param[] = {
2226            {.data = nullptr, .callback = NapiIsCallable},
2227        };
2228        JSVM_PropertyDescriptor descriptor[] = {
2229            {"napiIsCallable", NULL, &param[0], NULL, NULL, NULL, JSVM_DEFAULT},
2230        };
2231        // create env, register native method, and open env scope
2232        JSVM_Env env;
2233        OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env);
2234        JSVM_EnvScope envScope;
2235        OH_JSVM_OpenEnvScope(env, &envScope);
2236        // open handle scope
2237        JSVM_HandleScope handleScope;
2238        OH_JSVM_OpenHandleScope(env, &handleScope);
2239        std::string sourceCodeStr = R"JS(
2240        function addNumbers(num1, num2)
2241        {
2242            var rst= num1 + num2;
2243            return rst;
2244        }
2245        let rst = napiIsCallable(addNumbers);
2246        )JS";
2247        // compile js script
2248        JSVM_Value sourceCodeValue;
2249        OH_JSVM_CreateStringUtf8(env, sourceCodeStr.c_str(), sourceCodeStr.size(), &sourceCodeValue);
2250        JSVM_Script script;
2251        OH_JSVM_CompileScript(env, sourceCodeValue, nullptr, 0, true, nullptr, &script);
2252        JSVM_Value result;
2253        // run js script
2254        OH_JSVM_RunScript(env, script, &result);
2255        JSVM_ValueType type;
2256        OH_JSVM_Typeof(env, result, &type);
2257        OH_LOG_INFO(LOG_APP, "JSVM API TEST type: %{public}d", type);
2258        // exit vm and clean memory
2259        OH_JSVM_CloseHandleScope(env, handleScope);
2260        OH_JSVM_CloseEnvScope(env, envScope);
2261        OH_JSVM_DestroyEnv(env);
2262        OH_JSVM_CloseVMScope(vm, vmScope);
2263        OH_JSVM_DestroyVM(vm);
2264    });
2265    t.detach();
2266    return nullptr;
2267}
2268```
2269
2270### Lock操作
2271
2272#### 场景介绍
2273
2274Lock操作
2275
2276#### 接口说明
2277| 接口 | 功能说明 |
2278| -------- | -------- |
2279|OH_JSVM_IsLocked| 判断当前线程是否持有指定环境的锁 |
2280|OH_JSVM_AcquireLock| 获取指定环境的锁 |
2281|OH_JSVM_ReleaseLock| 释放指定环境的锁 |
2282
2283场景示例:
2284加锁解锁操作
2285
2286```c++
2287class LockWrapper {
2288 public:
2289  LockWrapper(JSVM_Env env) : env(env) {
2290    OH_JSVM_IsLocked(env, &isLocked);
2291    if (!isLocked) {
2292      OH_JSVM_AcquireLock(env);
2293      OH_JSVM_GetVM(env, &vm);
2294      OH_JSVM_OpenVMScope(vm, &vmScope);
2295      OH_JSVM_OpenEnvScope(env, &envScope);
2296    }
2297  }
2298
2299  ~LockWrapper() {
2300    if (!isLocked) {
2301      OH_JSVM_CloseEnvScope(env, envScope);
2302      OH_JSVM_CloseVMScope(vm, vmScope);
2303      OH_JSVM_ReleaseLock(env);
2304    }
2305  }
2306
2307  LockWrapper(const LockWrapper&) = delete;
2308  LockWrapper& operator=(const LockWrapper&) = delete;
2309  LockWrapper(LockWrapper&&) = delete;
2310  void* operator new(size_t) = delete;
2311  void* operator new[](size_t) = delete;
2312
2313 private:
2314  JSVM_Env env;
2315  JSVM_EnvScope envScope;
2316  JSVM_VMScope vmScope;
2317  JSVM_VM vm;
2318  bool isLocked;
2319};
2320
2321static napi_value Add([[maybe_unused]] napi_env _env, [[maybe_unused]] napi_callback_info _info) {
2322    static JSVM_VM vm;
2323    static JSVM_Env env;
2324    if (aa == 0) {
2325        OH_JSVM_Init(nullptr);
2326        aa++;
2327        // create vm
2328        JSVM_CreateVMOptions options;
2329        memset(&options, 0, sizeof(options));
2330        OH_JSVM_CreateVM(&options, &vm);
2331        // create env
2332        OH_JSVM_CreateEnv(vm, 0, nullptr, &env);
2333    }
2334
2335    std::thread t1([]() {
2336        LockWrapper lock(env);
2337        JSVM_HandleScope handleScope;
2338        OH_JSVM_OpenHandleScope(env, &handleScope);
2339        JSVM_Value value;
2340        JSVM_Status rst = OH_JSVM_CreateInt32(env, 32, &value); // 32: numerical value
2341        if (rst == JSVM_OK) {
2342            OH_LOG_INFO(LOG_APP, "JSVM:t1 OH_JSVM_CreateInt32 suc");
2343        } else {
2344            OH_LOG_ERROR(LOG_APP, "JSVM:t1 OH_JSVM_CreateInt32 fail");
2345        }
2346        int32_t num1;
2347        OH_JSVM_GetValueInt32(env, value, &num1);
2348        OH_LOG_INFO(LOG_APP, "JSVM:t1 num1 = %{public}d", num1);
2349        OH_JSVM_CloseHandleScope(env, handleScope);
2350    });
2351    std::thread t2([]() {
2352        LockWrapper lock(env);
2353        JSVM_HandleScope handleScope;
2354        OH_JSVM_OpenHandleScope(env, &handleScope);
2355        JSVM_Value value;
2356        JSVM_Status rst = OH_JSVM_CreateInt32(env, 32, &value); // 32: numerical value
2357        if (rst == JSVM_OK) {
2358            OH_LOG_INFO(LOG_APP, "JSVM:t2 OH_JSVM_CreateInt32 suc");
2359        } else {
2360            OH_LOG_ERROR(LOG_APP, "JSVM:t2 OH_JSVM_CreateInt32 fail");
2361        }
2362        int32_t num1;
2363        OH_JSVM_GetValueInt32(env, value, &num1);
2364        OH_LOG_INFO(LOG_APP, "JSVM:t2 num1 = %{public}d", num1);
2365        OH_JSVM_CloseHandleScope(env, handleScope);
2366    });
2367    t1.detach();
2368    t2.detach();
2369    return nullptr;
2370}
2371```
2372
2373### 设置与获取和当前运行的JSVM环境相关联的数据
2374
2375#### 场景介绍
2376
2377检索通过OH_JSVM_SetInstanceData()与当前运行的JSVM环境相关联的数据
2378
2379#### 接口说明
2380| 接口 | 功能说明 |
2381| -------- | -------- |
2382|OH_JSVM_SetInstanceData| 设置与当前运行的JSVM环境相关联的数据 |
2383|OH_JSVM_GetInstanceData| 获取与当前运行的JSVM环境相关联的数据 |
2384
2385场景示例:
2386设置并获取与当前运行的JSVM环境相关联的数据。
2387
2388```c++
2389JSVM_VM vm;
2390JSVM_CreateVMOptions options;
2391JSVM_VMScope vm_scope;
2392JSVM_Env env;
2393JSVM_EnvScope envScope;
2394JSVM_HandleScope handlescope;
2395
2396static int aa = 0;
2397struct InstanceData {
2398    int32_t value;
2399};
2400
2401// 初始化虚拟机,创建JSVM运行环境
2402void init_JSVM_environment(){
2403    JSVM_InitOptions init_options;
2404    memset(&init_options, 0, sizeof(init_options));
2405    if (aa == 0) {
2406        OH_JSVM_Init(&init_options);
2407        aa++;
2408    }
2409    memset(&options, 0, sizeof(options));
2410    OH_JSVM_CreateVM(&options, &vm);
2411    OH_JSVM_OpenVMScope(vm, &vm_scope);
2412    OH_JSVM_CreateEnv(vm, 0, nullptr, &env);
2413    OH_JSVM_OpenEnvScope(env, &envScope);
2414    OH_JSVM_OpenHandleScope(env, &handlescope);
2415}
2416
2417// 退出虚拟机,释放对应的环境
2418napi_value close_JSVM_environment(napi_env env1, napi_callback_info info)
2419{
2420    OH_JSVM_CloseHandleScope(env, handlescope);
2421    OH_JSVM_CloseEnvScope(env, envScope);
2422    OH_JSVM_DestroyEnv(env);
2423    OH_JSVM_CloseVMScope(vm, vm_scope);
2424    OH_JSVM_DestroyVM(vm);
2425    napi_value result;
2426    char* s = "ok";
2427    napi_create_string_latin1(env1, s, strlen(s), &result);
2428    return result;
2429}
2430
2431//清除和释放与实例相关联的内存资源
2432void InstanceFinalizeCallback(JSVM_Env env, void *finalizeData, void *finalizeHint)
2433{
2434    if (finalizeData) {
2435        InstanceData *data = reinterpret_cast<InstanceData *>(finalizeData);
2436        free(data);
2437        *(InstanceData **)finalizeData = nullptr;
2438    }
2439}
2440
2441static napi_value GetInstanceData(napi_env env1, napi_callback_info info)
2442{
2443    InstanceData *instanceData = reinterpret_cast<InstanceData *>(malloc(sizeof(InstanceData)));
2444    if (instanceData == nullptr) {
2445        printf("Memory allocation failed!\n");
2446        return nullptr;
2447    }
2448    size_t argc = 1;
2449    napi_value args[1] = {nullptr};
2450    //用于获取回调函数参数
2451    napi_get_cb_info(env1, info, &argc, args , nullptr, nullptr);
2452    napi_valuetype valuetype0;
2453    napi_typeof(env1, args[0], &valuetype0);
2454    int32_t tmp = 0;
2455    napi_get_value_int32(env1, args[0], &tmp);
2456    instanceData->value = tmp;
2457    //将获得的参数与当前运行的JSVM环境关联起来
2458    OH_JSVM_SetInstanceData(env, instanceData, InstanceFinalizeCallback, nullptr);
2459    InstanceData *resData = nullptr;
2460    //获取与当前运行的JSVM环境相关联的数据
2461    OH_JSVM_GetInstanceData(env, (void **)&resData);
2462    napi_value result;
2463    napi_create_uint32(env1, resData->value, &result);
2464    return result;
2465}
2466```
2467
2468### 任务队列
2469
2470#### 场景介绍
2471
2472在虚拟机内部启动任务队列的运行,检查是否有微任务在队列中等待,这个任务队列可以由外部事件循环执行
2473
2474#### 接口说明
2475| 接口 | 功能说明 |
2476| -------- | -------- |
2477|OH_JSVM_PumpMessageLoop| 启动任务队列的运行 |
2478|OH_JSVM_PerformMicrotaskCheckpoint| 执行任务队列里的微任务 |
2479
2480场景示例:
2481[启动任务队列,执行任务。](use-jsvm-execute_tasks.md)