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, ¶m[0], NULL, NULL, NULL, JSVM_DEFAULT}, 442 {"add", NULL, ¶m[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, ¶m, &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, ¶m, &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, ¶m1); 1479OH_JSVM_CreateStringUtf8(env, "b", JSVM_AUTO_LENGTH, ¶m2); 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, ¶m[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, ¶m1, 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, ¶m[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, ¶m1, 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, ¶m[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)