1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifdef TEST_WASM
16 #include <fstream>
17 #include <iostream>
18
19 #if defined(OHOS_JSVMTEST_XTS)
20 #define USE_HEADER_WASM
21 #endif
22
23 #include "jsvmtest.h"
24 #include "securec.h"
25 #ifdef USE_HEADER_WASM
26 #include <unordered_map>
27
28 #include "add.wasm.def"
29 #include "ammo.wasm.def"
30 #include "bfs.wasm.def"
31 #include "cJSON.wasm.def"
32 #include "global.wasm.def"
33 #include "illegal.wasm.def"
34 #include "illegal2.wasm.def"
35 #include "imports.wasm.def"
36 #include "laya.physics3D.wasm.def"
37 #include "math.wasm.def"
38 #include "memory.wasm.def"
39 #include "newton.wasm.def"
40 #include "reloc_info.wasm.def"
41 #include "simple.wasm.def"
42 #include "table.wasm.def"
43 #include "table2.wasm.def"
44 #endif
45
46 #if defined(USE_HEADER_WASM)
47 static const std::string wasmPath = "";
48
49 using WasmMap = std::unordered_map<std::string, std::pair<unsigned char *, unsigned int>>;
InitWasmMap()50 const WasmMap &InitWasmMap()
51 {
52 static WasmMap wasmMap{};
53 if (wasmMap.size() == 0) {
54 wasmMap["add.wasm"] = std::pair<unsigned char *, unsigned int>(add_wasm, add_wasm_len);
55 wasmMap["ammo.wasm.wasm"] = std::pair<unsigned char *, unsigned int>(ammo_wasm_wasm, ammo_wasm_wasm_len);
56 wasmMap["bfs.wasm"] = std::pair<unsigned char *, unsigned int>(bfs_wasm, bfs_wasm_len);
57 wasmMap["cJSON.wasm"] = std::pair<unsigned char *, unsigned int>(cJSON_wasm, cJSON_wasm_len);
58 wasmMap["global.wasm"] = std::pair<unsigned char *, unsigned int>(global_wasm, global_wasm_len);
59 wasmMap["illegal2.wasm"] = std::pair<unsigned char *, unsigned int>(illegal2_wasm, illegal2_wasm_len);
60 wasmMap["illegal.wasm"] = std::pair<unsigned char *, unsigned int>(illegal_wasm, illegal_wasm_len);
61 wasmMap["imports.wasm"] = std::pair<unsigned char *, unsigned int>(imports_wasm, imports_wasm_len);
62 wasmMap["laya.physics3D.wasm.wasm"] =
63 std::pair<unsigned char *, unsigned int>(laya_physics3D_wasm_wasm, laya_physics3D_wasm_wasm_len);
64 wasmMap["math.wasm"] = std::pair<unsigned char *, unsigned int>(math_wasm, math_wasm_len);
65 wasmMap["memory.wasm"] = std::pair<unsigned char *, unsigned int>(memory_wasm, memory_wasm_len);
66 wasmMap["newton.wasm"] = std::pair<unsigned char *, unsigned int>(newton_wasm, newton_wasm_len);
67 wasmMap["reloc_info.wasm"] = std::pair<unsigned char *, unsigned int>(reloc_info_wasm, reloc_info_wasm_len);
68 wasmMap["simple.wasm"] = std::pair<unsigned char *, unsigned int>(simple_wasm, simple_wasm_len);
69 wasmMap["table2.wasm"] = std::pair<unsigned char *, unsigned int>(table2_wasm, table2_wasm_len);
70 wasmMap["table.wasm"] = std::pair<unsigned char *, unsigned int>(table_wasm, table_wasm_len);
71 }
72 return wasmMap;
73 }
74
75 #elif defined(OHOS_JSVM_HAP)
76 static const std::string wasmPath = "/data/storage/el1/base/wasm/";
77 #else
78 static const std::string wasmPath = "./unittests/wasm/";
79 #endif
80
GetInstanceExports(JSVM_Value wasmInstance)81 static JSVM_Value GetInstanceExports(JSVM_Value wasmInstance)
82 {
83 CHECK(jsvm::IsWebAssemblyInstance(wasmInstance));
84 auto exports = jsvm::GetProperty(wasmInstance, "exports");
85 CHECK(jsvm::IsObject(exports));
86 return exports;
87 }
88
ReadBinaryFile(const char * path,std::vector<uint8_t> & buffer)89 static void ReadBinaryFile(const char *path, std::vector<uint8_t> &buffer)
90 {
91 #if !defined(USE_HEADER_WASM)
92 std::ifstream infile(path, std::ifstream::binary);
93 CHECK_FATAL(infile.good(), "can not access file: %s\n", path);
94 infile.seekg(0, std::ifstream::end);
95 size_t size = infile.tellg();
96 infile.seekg(0);
97 buffer.resize(size);
98 infile.read(reinterpret_cast<char *>(&buffer[0]), size);
99 infile.close();
100 #else
101 const auto &wasmMap = InitWasmMap();
102 auto it = wasmMap.find(path);
103 if (it == wasmMap.end()) {
104 CHECK_FATAL(false, "can not find file: %s", path);
105 }
106 auto p = it->second;
107 std::vector<uint8_t> newBuffer((uint8_t *)p.first, p.first + p.second);
108 buffer.swap(newBuffer);
109 #endif
110 }
111
ReadBinaryFile(const std::string & path,std::vector<uint8_t> & buffer)112 static void ReadBinaryFile(const std::string &path, std::vector<uint8_t> &buffer)
113 {
114 ReadBinaryFile(path.c_str(), buffer);
115 }
116
WriteBinaryFile(const char * path,const uint8_t * data,size_t byteLength)117 static void WriteBinaryFile(const char *path, const uint8_t *data, size_t byteLength)
118 {
119 std::ofstream outfile(path, std::ofstream::binary);
120 outfile.write(reinterpret_cast<const char *>(data), byteLength);
121 }
122
ReadTextFile(const char * path,std::string & content)123 static void ReadTextFile(const char *path, std::string &content)
124 {
125 std::ifstream infile(path);
126 CHECK_FATAL(infile.good(), "can not access file: %s\n", path);
127 std::ostringstream oss;
128 oss << infile.rdbuf();
129 content = oss.str();
130 }
131
ReadTextFile(const std::string & path,std::string & content)132 [[maybe_unused]] static void ReadTextFile(const std::string &path, std::string &content)
133 {
134 ReadTextFile(path.c_str(), content);
135 }
136
CompileWasmModule(const char * path)137 static JSVM_Value CompileWasmModule(const char *path)
138 {
139 std::vector<uint8_t> buffer;
140 ReadBinaryFile(path, buffer);
141 CHECK(buffer.size() > 0);
142 JSVM_Value wasmModule;
143 JSVMTEST_CALL(OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), NULL, 0, NULL, &wasmModule));
144 CHECK(jsvm::IsWasmModuleObject(wasmModule));
145 return wasmModule;
146 }
147
CompileWasmModule(const std::string & path)148 static JSVM_Value CompileWasmModule(const std::string &path)
149 {
150 return CompileWasmModule(path.c_str());
151 }
152
InstantiateWasmModule(JSVM_Value wasmModule,JSVM_Value importedObject)153 static JSVM_Value InstantiateWasmModule(JSVM_Value wasmModule, JSVM_Value importedObject)
154 {
155 auto globalThis = jsvm::Global();
156 auto WebAssembly = jsvm::GetProperty(globalThis, "WebAssembly");
157 CHECK(jsvm::IsObject(WebAssembly));
158 auto WebAssemblyInstance = jsvm::GetProperty(WebAssembly, "Instance");
159 CHECK(jsvm::IsFunction(WebAssemblyInstance));
160 JSVM_Value wasmInstance;
161 JSVM_Value argv[] = {wasmModule, importedObject};
162 constexpr size_t argc = 2;
163 JSVMTEST_CALL(OH_JSVM_NewInstance(jsvm_env, WebAssemblyInstance, argc, argv, &wasmInstance));
164 CHECK(jsvm::IsWebAssemblyInstance(wasmInstance));
165 return wasmInstance;
166 }
167
168 // [begin, end)
BatchCompileWasmFunctions(JSVM_Value wasmModule,size_t begin,size_t end)169 static void BatchCompileWasmFunctions(JSVM_Value wasmModule, size_t begin, size_t end)
170 {
171 CHECK(jsvm::IsWasmModuleObject(wasmModule));
172 for (size_t i = begin; i < end; ++i) {
173 JSVM_WasmOptLevel level = (i % 2 == 0 ? JSVM_WASM_OPT_BASELINE : JSVM_WASM_OPT_HIGH);
174 JSVMTEST_CALL(OH_JSVM_CompileWasmFunction(jsvm_env, wasmModule, i, level));
175 }
176 }
177
178 // 验证 wasm instance 功能 (add 模块)
VerifyAddWasmInstance(JSVM_Value instance)179 static void VerifyAddWasmInstance(JSVM_Value instance)
180 {
181 CHECK(jsvm::IsWebAssemblyInstance(instance));
182 // 实例化之后,就能使用 WebAssembly module 定义的函数了
183 auto exports = jsvm::GetProperty(instance, jsvm::Str("exports"));
184 CHECK(jsvm::IsObject(exports));
185 auto add = jsvm::GetProperty(exports, jsvm::Str("add"));
186 CHECK(jsvm::IsFunction(add));
187 auto result = jsvm::Call(add, jsvm::Undefined(), {jsvm::Run("1"), jsvm::Run("2")});
188 CHECK(jsvm::IsNumber(result));
189 constexpr int kExpectedResult = 3;
190 CHECK(jsvm::ToNumber(result) == kExpectedResult);
191 }
192
WebAssemblyDemo()193 static void WebAssemblyDemo()
194 {
195 std::string path = wasmPath + "add.wasm";
196 std::vector<uint8_t> buffer;
197 // 从文件中读取 wasm 字节码
198 ReadBinaryFile(path, buffer);
199 JSVM_Status status = JSVM_OK;
200
201 JSVM_Value wasmModule;
202 // 将 wasm 字节码编译为 WebAssembly module
203 status = OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), NULL, 0, NULL, &wasmModule);
204 CHECK(status == JSVM_OK);
205
206 bool isWasmModule;
207 // 检查编译结果确实是一个 WebAssembly module
208 status = OH_JSVM_IsWasmModuleObject(jsvm_env, wasmModule, &isWasmModule);
209 CHECK(status == JSVM_OK);
210 CHECK(isWasmModule);
211
212 // 对 WebAssembly module 指定编号的函数进行 high optimization level 优化
213 status = OH_JSVM_CompileWasmFunction(jsvm_env, wasmModule, 0, JSVM_WASM_OPT_HIGH);
214 CHECK(status == JSVM_OK);
215
216 // 实例化 WebAssembly module
217 auto instance = InstantiateWasmModule(wasmModule, jsvm::Run("{}"));
218 VerifyAddWasmInstance(instance);
219
220 // 对编译后的 WebAssembly moudle 进行序列化,创建 wasm cache
221 const uint8_t *cacheData = NULL;
222 size_t cacheLength = 0;
223 status = OH_JSVM_CreateWasmCache(jsvm_env, wasmModule, &cacheData, &cacheLength);
224 CHECK(status == JSVM_OK);
225 CHECK(cacheData != NULL);
226 CHECK(cacheLength > 0);
227
228 // 对序列化得到的 cache data 进行持久化存储
229 const std::string wasmCachePath = path + ".cache";
230 WriteBinaryFile(wasmCachePath.c_str(), cacheData, cacheLength);
231 status = OH_JSVM_ReleaseCache(jsvm_env, cacheData, JSVM_CACHE_TYPE_WASM);
232 CHECK(status == JSVM_OK);
233
234 // 下次使用时,直接使用 wasm cache 反序列化得到 WebAssembly module,避免编译开销
235 std::vector<uint8_t> cacheBuffer;
236 ReadBinaryFile(wasmCachePath, cacheBuffer);
237 CHECK(cacheBuffer.size() == cacheLength);
238
239 bool cacheRejected;
240 JSVM_Value wasmModuleSerialized;
241 status = OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), cacheBuffer.data(), cacheBuffer.size(),
242 &cacheRejected, &wasmModuleSerialized);
243 CHECK(status == JSVM_OK);
244
245 CHECK(cacheRejected == false);
246 status = OH_JSVM_IsWasmModuleObject(jsvm_env, wasmModuleSerialized, &isWasmModule);
247 CHECK(status == JSVM_OK);
248 CHECK(isWasmModule);
249
250 // 测试反序列化而来的 WebAssembly module 的功能
251 // 实例化 WebAssembly module
252 auto instance2 = InstantiateWasmModule(wasmModuleSerialized, jsvm::Run("var x = {}; x"));
253 VerifyAddWasmInstance(instance2);
254 }
255
256 #if !defined(JSVM_JITLESS)
257 // test for Wasm Is Wasm Module Object
TEST(Wasm_IsWasmModuleObject)258 TEST(Wasm_IsWasmModuleObject)
259 {
260 auto number = jsvm::Run("42");
261 CHECK(!jsvm::IsWasmModuleObject(number));
262 CHECK(!jsvm::IsWasmModuleObject(jsvm::Undefined()));
263 CHECK(!jsvm::IsWasmModuleObject(jsvm::Null()));
264 CHECK(!jsvm::IsWasmModuleObject(jsvm::Str("hello")));
265 }
266
267 #ifdef OHOS_JSVMTEST_XTS
TEST_DISABLE(Wasm_WebAssemblyDemo)268 TEST_DISABLE(Wasm_WebAssemblyDemo)
269 {
270 #else
271 TEST(Wasm_WebAssemblyDemo)
272 {
273 #endif
274 WebAssemblyDemo();
275 }
276
277 // test for Wasm Compile Wasm Module
278 TEST(Wasm_CompileWasmModule)
279 {
280 JSVM_Value wasmModule = CompileWasmModule(wasmPath + "add.wasm");
281 JSVM_Value wasmInstance = InstantiateWasmModule(wasmModule, jsvm::Run("{}"));
282 JSVM_Value exports = jsvm::GetProperty(wasmInstance, jsvm::Str("exports"));
283 CHECK(jsvm::IsObject(exports));
284 JSVM_Value addFunc = jsvm::GetProperty(exports, jsvm::Str("add"));
285 CHECK(jsvm::IsFunction(addFunc));
286 JSVM_Value one = jsvm::Run("1");
287 JSVM_Value two = jsvm::Run("2");
288 JSVM_Value result = jsvm::Call(addFunc, jsvm::Undefined(), {one, two});
289 CHECK(jsvm::ToNumber(result) == 3);
290
291 JSVMTEST_CALL(OH_JSVM_CompileWasmFunction(env, wasmModule, 0, JSVM_WASM_OPT_HIGH));
292
293 const uint8_t *cacheData = nullptr;
294 size_t cacheSize = 0;
295 JSVMTEST_CALL(OH_JSVM_CreateWasmCache(env, wasmModule, &cacheData, &cacheSize));
296 CHECK(cacheData != nullptr);
297 CHECK(cacheSize > 0);
298 }
299
300 [[maybe_unused]] static void RandomDeserialize(JSVM_Env env, const std::string &filename)
301 {
302 std::string wasmFile = wasmPath + filename;
303 std::string cacheFile = wasmPath + filename + ".test.cache";
304 std::ifstream infile(cacheFile);
305 if (!infile.good()) {
306 // CreateCodeCache
307 auto wasmModule = CompileWasmModule(wasmFile);
308 InstantiateWasmModule(wasmModule, jsvm::Undefined());
309 JSVMTEST_CALL(OH_JSVM_CompileWasmFunction(env, wasmModule, 0, JSVM_WASM_OPT_HIGH));
310 const uint8_t *data = NULL;
311 size_t length = 0;
312 JSVMTEST_CALL(OH_JSVM_CreateWasmCache(env, wasmModule, &data, &length));
313 CHECK(data != NULL);
314 CHECK(length > 0);
315 WriteBinaryFile(cacheFile.c_str(), data, length);
316 JSVMTEST_CALL(OH_JSVM_ReleaseCache(env, data, JSVM_CACHE_TYPE_WASM));
317 } else {
318 std::vector<uint8_t> buffer;
319 ReadBinaryFile(wasmFile, buffer);
320 std::vector<uint8_t> cache;
321 ReadBinaryFile(cacheFile, cache);
322 JSVM_Value wasmModule;
323 bool cacheRejected;
324 JSVMTEST_CALL(OH_JSVM_CompileWasmModule(env, buffer.data(), buffer.size(), cache.data(), cache.size(),
325 &cacheRejected, &wasmModule));
326 CHECK(cacheRejected == false);
327 CHECK(jsvm::IsWasmModuleObject(wasmModule));
328 // 运行一定次数后,删除缓存
329 constexpr int kPeriodToRemoveCache = 3;
330 static int cnt = 0;
331 if (++cnt % kPeriodToRemoveCache == 0) {
332 int result = remove(cacheFile.c_str());
333 CHECK(result == 0);
334 }
335 }
336 }
337
338 // test for Wasm Random Cache Test
339 #ifdef OHOS_JSVMTEST_XTS
340 TEST_DISABLE(Wasm_RandomCacheTest)
341 {
342 #else
343 TEST(Wasm_RandomCacheTest)
344 {
345 #endif
346 static std::vector<std::string> allFiles = {
347 "add.wasm",
348 "bfs.wasm",
349 "cJSON.wasm",
350 "math.wasm",
351 };
352 for (const std::string &filename : allFiles) {
353 for (int i = 0; i < 100; ++i) {
354 RandomDeserialize(env, filename);
355 }
356 }
357 }
358
359 // test for Wasm Compile Wasm Function Baseline
360 TEST(Wasm_CompileWasmFunctionBaseline)
361 {
362 auto wasmModule = CompileWasmModule(wasmPath + "add.wasm");
363 InstantiateWasmModule(wasmModule, jsvm::Undefined());
364 JSVMTEST_CALL(OH_JSVM_CompileWasmFunction(env, wasmModule, 0, JSVM_WASM_OPT_BASELINE));
365 JSVMTEST_CALL(OH_JSVM_CompileWasmFunction(env, wasmModule, 0, JSVM_WASM_OPT_HIGH));
366 auto status = OH_JSVM_CompileWasmFunction(env, wasmModule, 1, JSVM_WASM_OPT_HIGH);
367 CHECK(status != JSVM_OK);
368 }
369
370 // test for Wasm Compile Illegal Wasm Module
371 TEST(Wasm_CompileIllegalWasmModule)
372 {
373 std::vector<uint8_t> buffer;
374 std::vector<std::string> pathVec = {
375 wasmPath + "illegal.wasm",
376 wasmPath + "illegal2.wasm",
377 };
378 for (const std::string &path : pathVec) {
379 ReadBinaryFile(path, buffer);
380 CHECK(buffer.size() > 0);
381 JSVM_Value wasmModule;
382 JSVM_Status status =
383 OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), NULL, 0, NULL, &wasmModule);
384 CHECK(status == JSVM_PENDING_EXCEPTION);
385 }
386 }
387
388 // Test import global
389 static void TestImportGlobal(JSVM_Env env, JSVM_Value exports)
390 {
391 JSVM_Value testFunc;
392 JSVM_Value result;
393 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_global_i32"));
394 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
395 CHECK(jsvm::Equals(result, jsvm::Run("100")));
396
397 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_global_i64"));
398 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
399 CHECK(jsvm::Equals(result, jsvm::Run("1000000000000000n")));
400
401 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_global_f32"));
402 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
403
404 JSVM_ValueType type;
405 OH_JSVM_Typeof(env, result, &type);
406 CHECK(jsvm::Equals(result, jsvm::Run("new Float32Array([1.3])[0]")));
407
408 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_global_f64"));
409 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
410 CHECK(jsvm::Equals(result, jsvm::Run("2.7")));
411 }
412
413 // Test import func
414 static void TestImportFunc(JSVM_Env env, JSVM_Value exports)
415 {
416 (void)env;
417 JSVM_Value testFunc;
418 JSVM_Value result;
419 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_sub"));
420 result = jsvm::Call(testFunc, jsvm::Undefined(), {jsvm::Run("1"), jsvm::Run("2")});
421 CHECK(jsvm::Equals(result, jsvm::Run("-1")));
422 }
423
424 // Test import memory
425 static void TestImportMemory(JSVM_Env env, JSVM_Value exports)
426 {
427 JSVM_Value testFunc;
428 JSVM_Value result;
429 JSVM_Status status = JSVM_OK;
430 JSVM_Value exception;
431 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_memory"));
432 result = jsvm::Call(testFunc, jsvm::Undefined(), {jsvm::Run("0")});
433 CHECK(jsvm::Equals(result, jsvm::Run("0")));
434
435 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_memory"));
436 result = jsvm::Call(testFunc, jsvm::Undefined(), {jsvm::Run("10")});
437 CHECK(jsvm::Equals(result, jsvm::Run("16")));
438
439 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_memory"));
440 result = jsvm::Call(testFunc, jsvm::Undefined(), {jsvm::Run("8")});
441 CHECK(jsvm::Equals(result, jsvm::Run("1048576")));
442
443 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_memory"));
444 JSVM_Value argv[1] = {jsvm::Run("1000000")};
445 status = OH_JSVM_CallFunction(jsvm_env, jsvm::Undefined(), testFunc, 1, argv, &result);
446 CHECK(status == JSVM_PENDING_EXCEPTION);
447 status = OH_JSVM_GetAndClearLastException(env, &exception);
448 }
449
450 // Test import table
451 static void TestImportTable(JSVM_Env env, JSVM_Value exports)
452 {
453 JSVM_Value testFunc;
454 JSVM_Value result;
455 JSVM_Status status = JSVM_OK;
456 JSVM_Value exception;
457 {
458 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_table"));
459 JSVM_Value argv[1] = {jsvm::Run("0")};
460 status = OH_JSVM_CallFunction(jsvm_env, jsvm::Undefined(), testFunc, 1, argv, &result);
461 CHECK(status == JSVM_PENDING_EXCEPTION);
462 OH_JSVM_GetAndClearLastException(env, &exception);
463 }
464
465 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_table"));
466 result = jsvm::Call(testFunc, jsvm::Undefined(), {jsvm::Run("1")});
467 CHECK(jsvm::Equals(result, jsvm::Run("11")));
468
469 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_table"));
470 result = jsvm::Call(testFunc, jsvm::Undefined(), {jsvm::Run("2")});
471 CHECK(jsvm::Equals(result, jsvm::Run("22")));
472
473 {
474 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_table"));
475 JSVM_Value argv[1] = {jsvm::Run("3")};
476 status = OH_JSVM_CallFunction(jsvm_env, jsvm::Undefined(), testFunc, 1, argv, &result);
477 CHECK(status == JSVM_PENDING_EXCEPTION);
478 OH_JSVM_GetAndClearLastException(env, &exception);
479 }
480
481 {
482 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_table"));
483 JSVM_Value argv[1] = {jsvm::Run("100")};
484 status = OH_JSVM_CallFunction(jsvm_env, jsvm::Undefined(), testFunc, 1, argv, &result);
485 CHECK(status == JSVM_PENDING_EXCEPTION);
486 OH_JSVM_GetAndClearLastException(env, &exception);
487 }
488 }
489
490 // test for Wasm Compile Wasm Module With Imports
491 TEST(Wasm_CompileWasmModuleWithImports)
492 {
493 JSVM_Value wasmModule = CompileWasmModule(wasmPath + "imports.wasm");
494 const char *importJs = R"JS(
495 var x = {
496 test: {
497 global_i32: 100,
498 global_i64: 1000000000000000n,
499 global_f32: 1.3,
500 global_f64: 2.7,
501 sub: (a, b) => { return a - b; },
502 memory: new WebAssembly.Memory({initial: 1, maximum: 2}),
503 table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}),
504 }
505 };
506 x
507 )JS";
508
509 JSVM_Value importedObj = jsvm::Run(importJs);
510
511 CHECK(jsvm::IsObject(importedObj));
512 JSVM_Value wasmInstance = InstantiateWasmModule(wasmModule, importedObj);
513 JSVM_Value exports = jsvm::GetProperty(wasmInstance, jsvm::Str("exports"));
514 CHECK(jsvm::IsObject(exports));
515
516 TestImportGlobal(env, exports);
517 TestImportFunc(env, exports);
518 TestImportMemory(env, exports);
519 TestImportTable(env, exports);
520 }
521
522 static void CompileWasmFunctions(JSVM_Env env, JSVM_Value wasmModule,
523 const std::initializer_list<uint32_t> &funcIndexList, JSVM_WasmOptLevel optLevel)
524 {
525 for (uint32_t funcIndex : funcIndexList) {
526 JSVM_Status status = OH_JSVM_CompileWasmFunction(jsvm_env, wasmModule, funcIndex, optLevel);
527 CHECK(status == JSVM_OK);
528 }
529 }
530
531 static JSVM_Value TestCacheAndRelocInfoStep1(JSVM_Env env, const std::vector<uint8_t> &buffer,
532 const uint8_t *&cacheData, size_t &cacheSize)
533 {
534 JSVM_Value wasmModule;
535 JSVMTEST_CALL(OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), NULL, 0, NULL, &wasmModule));
536 CHECK(jsvm::IsWasmModuleObject(wasmModule));
537
538 JSVM_Value wasmInstance =
539 InstantiateWasmModule(wasmModule, jsvm::Run("var x = { test: {func: () => { return 1; }}}; x"));
540 JSVM_Value exports = jsvm::GetProperty(wasmInstance, jsvm::Str("exports"));
541 CHECK(jsvm::IsObject(exports));
542
543 CompileWasmFunctions(env, wasmModule, {1, 2}, JSVM_WASM_OPT_HIGH);
544
545 JSVM_Value testFunc;
546 JSVM_Value result;
547 {
548 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_wasm_call_reloc_info"));
549 CHECK(jsvm::IsFunction(testFunc));
550 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
551 CHECK(jsvm::Equals(result, jsvm::Run("1")));
552
553 testFunc = jsvm::GetProperty(exports, jsvm::Str("test_wasm_stub_call_reloc_info"));
554 CHECK(jsvm::IsFunction(testFunc));
555 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
556 CHECK(jsvm::Equals(result, jsvm::Run("1")));
557 }
558 JSVMTEST_CALL(OH_JSVM_CreateWasmCache(env, wasmModule, &cacheData, &cacheSize));
559 CHECK(cacheData != nullptr);
560 CHECK(cacheSize > 0);
561 return exports;
562 }
563
564 static void TestCacheAndRelocInfoStep2(JSVM_Env env, const std::vector<uint8_t> &buffer, const uint8_t *cacheData,
565 size_t cacheSize, JSVM_Value exports)
566 {
567 bool cacheRejected;
568 JSVM_Value wasmModule;
569 JSVM_Status status = OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), cacheData, cacheSize,
570 &cacheRejected, &wasmModule);
571 CHECK(status == JSVM_OK);
572 CHECK(cacheRejected == false);
573
574 JSVM_Value wasmInstance =
575 InstantiateWasmModule(wasmModule, jsvm::Run("var x = { test: {func: () => { return 2; }}}; x"));
576
577 JSVM_Value newExports = jsvm::GetProperty(wasmInstance, jsvm::Str("exports"));
578 JSVM_Value testFunc;
579 JSVM_Value result;
580
581 {
582 testFunc = jsvm::GetProperty(newExports, jsvm::Str("test_wasm_call_reloc_info"));
583 CHECK(jsvm::IsFunction(testFunc));
584 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
585 CHECK(jsvm::Equals(result, jsvm::Run("1")));
586
587 testFunc = jsvm::GetProperty(newExports, jsvm::Str("test_wasm_stub_call_reloc_info"));
588 CHECK(jsvm::IsFunction(testFunc));
589 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
590 CHECK(jsvm::Equals(result, jsvm::Run("1")));
591 }
592
593 testFunc = jsvm::GetProperty(exports, jsvm::Str("call_import"));
594 CHECK(jsvm::IsFunction(testFunc));
595 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
596 CHECK(jsvm::Equals(result, jsvm::Run("1")));
597
598 testFunc = jsvm::GetProperty(newExports, jsvm::Str("call_import"));
599 CHECK(jsvm::IsFunction(testFunc));
600 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
601 CHECK(jsvm::Equals(result, jsvm::Run("2")));
602
603 CompileWasmFunctions(env, wasmModule, {1, 2}, JSVM_WASM_OPT_HIGH);
604 CompileWasmFunctions(env, wasmModule, {1, 2}, JSVM_WASM_OPT_HIGH);
605
606 status = OH_JSVM_ReleaseCache(jsvm_env, cacheData, JSVM_CACHE_TYPE_WASM);
607 CHECK(status == JSVM_OK);
608 }
609
610 // test for Wasm Compile Wasm Module With Cache And Reloc Info
611 TEST(Wasm_CompileWasmModuleWithCacheAndRelocInfo)
612 {
613 std::vector<uint8_t> buffer;
614 ReadBinaryFile(wasmPath + "reloc_info.wasm", buffer);
615 CHECK(buffer.size() > 0);
616
617 const uint8_t *cacheData = NULL;
618 size_t cacheSize = 0;
619 JSVM_Value exports = TestCacheAndRelocInfoStep1(env, buffer, cacheData, cacheSize);
620 TestCacheAndRelocInfoStep2(env, buffer, cacheData, cacheSize, exports);
621 }
622
623 // test for Wasm Multiple Instances
624 TEST(Wasm_MultipleInstances)
625 {
626 auto wasmModule = CompileWasmModule(wasmPath + "add.wasm");
627 {
628 auto obj = jsvm::Run("var x = { foo : 'bar' }; x");
629 CHECK(jsvm::IsObject(obj));
630 auto instance = InstantiateWasmModule(wasmModule, obj);
631 CHECK(jsvm::IsWebAssemblyInstance(instance));
632 }
633 {
634 auto obj = jsvm::Run("var x = { a : 1 }; x");
635 CHECK(jsvm::IsObject(obj));
636 auto instance = InstantiateWasmModule(wasmModule, obj);
637 CHECK(jsvm::IsWebAssemblyInstance(instance));
638 }
639 {
640 auto obj = jsvm::Run("var x = { b : 2 }; x");
641 CHECK(jsvm::IsObject(obj));
642 auto instance = InstantiateWasmModule(wasmModule, obj);
643 CHECK(jsvm::IsWebAssemblyInstance(instance));
644 }
645 }
646
647 static std::string fakelog = "";
648
649 static JSVM_Value FakeConsoleLog(JSVM_Env env, JSVM_CallbackInfo info)
650 {
651 size_t argc = 1;
652 JSVM_Value argv[1];
653 JSVMTEST_CALL(OH_JSVM_GetCbInfo(env, info, &argc, argv, NULL, NULL));
654 JSVM_Value x = argv[0];
655 fakelog = jsvm::ToString(x);
656 return jsvm::Undefined();
657 }
658
659 static void InstallFakeConsoleLog(JSVM_Env env)
660 {
661 static JSVM_CallbackStruct cb = {FakeConsoleLog, NULL};
662 JSVM_Value log;
663 JSVMTEST_CALL(OH_JSVM_CreateFunction(env, "log", JSVM_AUTO_LENGTH, &cb, &log));
664 CHECK(jsvm::IsFunction(log));
665 auto console = jsvm::Global("console");
666 if (!jsvm::IsObject(console)) {
667 JSVMTEST_CALL(OH_JSVM_CreateObject(env, &console));
668 jsvm::SetProperty(jsvm::Global(), "console", console);
669 }
670 jsvm::SetProperty(console, "log", log);
671 }
672
673 // test for Wasm MDN index
674 TEST(Wasm_MDN_index)
675 {
676 fakelog = "";
677 InstallFakeConsoleLog(env);
678 auto wasmModule = CompileWasmModule(wasmPath + "simple.wasm");
679 auto importObj = jsvm::Run(R"JS(
680 var importObject = {
681 my_namespace: {
682 imported_func: arg => {
683 console.log(arg);
684 }
685 }
686 };
687 importObject;
688 )JS");
689 CHECK(jsvm::IsObject(importObj));
690 auto instance = InstantiateWasmModule(wasmModule, importObj);
691 auto exports = jsvm::GetProperty(instance, jsvm::Str("exports"));
692 auto exported_func = jsvm::GetProperty(exports, jsvm::Str("exported_func"));
693 CHECK(fakelog == "");
694 jsvm::Call(exported_func); // expected console.log 42
695 CHECK(fakelog == "42");
696 }
697
698 // test for Wasm MDN imports
699 TEST(Wasm_MDN_imports)
700 {
701 auto wasmModule = CompileWasmModule(wasmPath + "simple.wasm");
702 auto WebAssembly = jsvm::GetProperty(jsvm::Global(), jsvm::Str("WebAssembly"));
703 auto Module = jsvm::GetProperty(WebAssembly, jsvm::Str("Module"));
704 auto ModuleImports = jsvm::GetProperty(Module, jsvm::Str("imports"));
705 CHECK(jsvm::IsFunction(ModuleImports));
706 auto imports = jsvm::Call(ModuleImports, Module, {wasmModule});
707 CHECK(jsvm::IsArray(imports));
708 JSVM_Value element;
709 JSVMTEST_CALL(OH_JSVM_GetElement(env, imports, 0, &element));
710 CHECK(jsvm::IsObject(element));
711 }
712
713 // test for Wasm MDN validate
714 TEST(Wasm_MDN_validate)
715 {
716 std::vector<uint8_t> buffer;
717 ReadBinaryFile(wasmPath + "simple.wasm", buffer);
718 CHECK(buffer.size() > 0);
719 void *backingStoreData = NULL;
720 JSVM_Value arraybuffer;
721 JSVMTEST_CALL(OH_JSVM_CreateArraybuffer(env, buffer.size(), &backingStoreData, &arraybuffer));
722 memcpy_s(backingStoreData, buffer.size(), buffer.data(), buffer.size());
723 CHECK(jsvm::IsArraybuffer(arraybuffer));
724
725 auto WebAssembly = jsvm::Global("WebAssembly");
726 auto validate = jsvm::GetProperty(WebAssembly, "validate");
727 auto isValid = jsvm::Call(validate, WebAssembly, {arraybuffer});
728 CHECK(jsvm::IsBoolean(isValid));
729 CHECK(jsvm::StrictEquals(isValid, jsvm::True()));
730 }
731
732 // test for Wasm MDN memory
733 TEST(Wasm_MDN_memory)
734 {
735 (void)jsvm::Run(R"JS(
736 var memory = new WebAssembly.Memory({
737 initial: 10,
738 maximum: 100,
739 });
740 memory
741 )JS");
742 auto x = jsvm::GetProperty(jsvm::Global(), jsvm::Str("memory"));
743 CHECK(jsvm::IsObject(x));
744 auto importObject = jsvm::Run(R"JS(
745 var importObject = {
746 js: {
747 mem: memory
748 }
749 };
750 importObject
751 )JS");
752 auto wasmModule = CompileWasmModule(wasmPath + "memory.wasm");
753 auto instance = InstantiateWasmModule(wasmModule, importObject);
754
755 jsvm::Run(R"JS(
756 var summands = new DataView(memory.buffer);
757 for (var i = 0; i < 10; ++i) {
758 summands.setUint32(i * 4, i, true); // WebAssembly is little endian
759 }
760 )JS");
761
762 auto exports = GetInstanceExports(instance);
763 auto accumulate = jsvm::GetProperty(exports, jsvm::Str("accumulate"));
764 CHECK(jsvm::IsFunction(accumulate));
765 auto result = jsvm::Call(accumulate, exports, {jsvm::Int32(0), jsvm::Int32(10)});
766 CHECK(jsvm::IsNumber(result));
767 CHECK(jsvm::ToNumber(result) == 45);
768 }
769
770 // test for Wasm MDN table
771 TEST(Wasm_MDN_table)
772 {
773 auto table = jsvm::Run(R"JS(
774 var table = new WebAssembly.Table({
775 element: "anyfunc",
776 initial: 1,
777 maximum: 10
778 });
779 table.grow(1);
780 table;
781 )JS");
782 CHECK(jsvm::IsWebAssemblyTable(table));
783 auto wasmModule = CompileWasmModule(wasmPath + "table.wasm");
784 auto instance = InstantiateWasmModule(wasmModule, jsvm::Undefined());
785 auto exports = GetInstanceExports(instance);
786 auto tbl = jsvm::GetProperty(exports, jsvm::Str("tbl"));
787 jsvm::SetProperty(jsvm::Global(), jsvm::Str("tbl"), tbl);
788 auto r0 = jsvm::Run("tbl.get(0)()");
789 CHECK(jsvm::ToNumber(r0) == 13);
790 auto r1 = jsvm::Run("tbl.get(1)()");
791 CHECK(jsvm::ToNumber(r1) == 42);
792 }
793
794 // test for Wasm MDN table2
795 TEST(Wasm_MDN_table2)
796 {
797 auto tbl = jsvm::Run(R"JS(
798 var tbl = new WebAssembly.Table({
799 initial: 2,
800 element: "anyfunc"
801 });
802 tbl;
803 )JS");
804 CHECK(jsvm::IsWebAssemblyTable(tbl));
805
806 auto importObject = jsvm::Run(R"JS(
807 var importObject = {
808 js: { tbl }
809 };
810 importObject;
811 )JS");
812 CHECK(jsvm::IsObject(importObject));
813
814 auto wasmModule = CompileWasmModule(wasmPath + "table2.wasm");
815 (void)InstantiateWasmModule(wasmModule, importObject);
816 auto r0 = jsvm::Run("tbl.get(0)()");
817 CHECK(jsvm::ToNumber(r0) == 42);
818 auto r1 = jsvm::Run("tbl.get(1)()");
819 CHECK(jsvm::ToNumber(r1) == 83);
820 }
821
822 // test for Wasm MDN global
823 TEST(Wasm_MDN_global)
824 {
825 (void)jsvm::Run("var global = new WebAssembly.Global({ value: 'i32', mutable: true }, 0); global");
826 auto wasmModule = CompileWasmModule(wasmPath + "global.wasm");
827 auto importObject = jsvm::Run(R"JS(
828 var importObject = {
829 js: { global }
830 };
831 importObject
832 )JS");
833 auto instance = InstantiateWasmModule(wasmModule, importObject);
834 auto exports = GetInstanceExports(instance);
835 auto getGlobal = jsvm::GetProperty(exports, "getGlobal");
836 CHECK(jsvm::IsFunction(getGlobal));
837 auto r0 = jsvm::Call(getGlobal, exports, {});
838 CHECK(jsvm::ToNumber(r0) == 0);
839 jsvm::Run("global.value = 42");
840 auto r1 = jsvm::Call(getGlobal, exports, {});
841 CHECK(jsvm::ToNumber(r1) == 42);
842 auto incGlobal = jsvm::GetProperty(exports, "incGlobal");
843 jsvm::Call(incGlobal, exports, {});
844 auto r2 = jsvm::Call(getGlobal, exports, {});
845 CHECK(jsvm::ToNumber(r2) == 43);
846 }
847
848 // test for Wasm Multiple Modules
849 TEST(Wasm_MultipleModules)
850 {
851 auto mathModule = CompileWasmModule(wasmPath + "math.wasm");
852 auto newtonModule = CompileWasmModule(wasmPath + "newton.wasm");
853 auto mathInstance = InstantiateWasmModule(mathModule, jsvm::Undefined());
854 auto mathExports = GetInstanceExports(mathInstance);
855 auto add = jsvm::GetProperty(mathExports, "add");
856 CHECK(jsvm::IsFunction(add));
857 auto sub = jsvm::GetProperty(mathExports, "sub");
858 CHECK(jsvm::IsFunction(sub));
859 jsvm::SetProperty(jsvm::Global(), jsvm::Str("add"), add);
860 jsvm::SetProperty(jsvm::Global(), jsvm::Str("sub"), sub);
861 auto mathObj = jsvm::Run(R"JS(
862 var mathObj = {
863 math: {
864 add: add,
865 sub, sub
866 }
867 };
868 mathObj
869 )JS");
870 CHECK(jsvm::IsObject(mathObj));
871 auto newtonInstance = InstantiateWasmModule(newtonModule, mathObj);
872 auto newtonExports = GetInstanceExports(newtonInstance);
873 auto calculate = jsvm::GetProperty(newtonExports, "calculate");
874 CHECK(jsvm::IsFunction(calculate));
875 auto result = jsvm::Call(calculate);
876 CHECK(jsvm::IsNumber(result));
877 CHECK(jsvm::ToNumber(result) == 42);
878 }
879
880 void runCToWasm(JSVM_Env env, const std::string& filePath)
881 {
882 std::vector<uint8_t> buffer;
883 ReadBinaryFile(filePath, buffer);
884 CHECK(buffer.size() > 0);
885 JSVM_Value wasmModule;
886 JSVMTEST_CALL(OH_JSVM_CompileWasmModule(jsvm_env, buffer.data(), buffer.size(), NULL, 0, NULL, &wasmModule));
887 CHECK(jsvm::IsWasmModuleObject(wasmModule));
888
889 JSVM_Value wasmInstance =
890 InstantiateWasmModule(wasmModule, jsvm::Run("var x = { test: {func: () => { return 1; }}}; x"));
891 JSVM_Value exports = jsvm::GetProperty(wasmInstance, jsvm::Str("exports"));
892 CHECK(jsvm::IsObject(exports));
893
894 CompileWasmFunctions(env, wasmModule, {1, 2}, JSVM_WASM_OPT_HIGH);
895
896 JSVM_Value testFunc;
897 JSVM_Value result;
898 {
899 testFunc = jsvm::GetProperty(exports, jsvm::Str("_start"));
900 CHECK(jsvm::IsFunction(testFunc));
901 result = jsvm::Call(testFunc, jsvm::Undefined(), {});
902 CHECK(jsvm::Equals(result, jsvm::Undefined()));
903 }
904 }
905
906 // test for Wasm Run CTo Wasm Test
907 TEST(Wasm_RunCToWasmTest)
908 {
909 std::vector<std::string> pathVec = {
910 wasmPath + "bfs.wasm",
911 wasmPath + "cJSON.wasm",
912 };
913
914 for (std::string &wasm : pathVec) {
915 runCToWasm(env, wasm);
916 }
917 }
918
919 // test for Wasm Game Engine Ammo
920 TEST(Wasm_GameEngineAmmo)
921 {
922 std::string wasmFile = wasmPath + "ammo.wasm.wasm";
923 auto wasmModule = CompileWasmModule(wasmFile);
924 const char *str = R"JS(
925 var obj = {
926 f: () => {},
927 c: () => {},
928 d: () => {},
929 e: () => {},
930 b: () => {},
931 g: () => {},
932 a: () => {},
933 memory: new WebAssembly.Memory({initial: 1024, maximum: 1024}),
934 table: new WebAssembly.Table({ initial: 758, element: "anyfunc" })
935 };
936 var importObj = {
937 env: obj,
938 wasi_unstable: obj
939 };
940 importObj;
941 )JS";
942 auto importObj = jsvm::Run(str);
943 auto instance = InstantiateWasmModule(wasmModule, importObj);
944 CHECK(jsvm::IsWebAssemblyInstance(instance));
945 BatchCompileWasmFunctions(wasmModule, 7, 20);
946 BatchCompileWasmFunctions(wasmModule, 400, 420);
947 BatchCompileWasmFunctions(wasmModule, 1480, 1502);
948 auto exports = GetInstanceExports(instance);
949 CHECK(jsvm::IsObject(exports));
950 }
951
952 // test for Wasm Game Engine Laya
953 TEST(Wasm_GameEngineLaya)
954 {
955 std::string wasmFile = wasmPath + "laya.physics3D.wasm.wasm";
956 auto wasmModule = CompileWasmModule(wasmFile);
957 const char *str = R"JS(
958 var importObj = {
959 env: {
960 memory: new WebAssembly.Memory({initial: 2}),
961 },
962 wasi_unstable: {
963 fd_close: () => {},
964 fd_write: () => {},
965 fd_seek: () => {},
966 },
967 LayaAirInteractive: {
968 getWorldTransform: () => {},
969 setWorldTransform: () => {},
970 }
971 };
972 importObj;
973 )JS";
974 auto importObj = jsvm::Run(str);
975 auto instance = InstantiateWasmModule(wasmModule, importObj);
976 CHECK(jsvm::IsWebAssemblyInstance(instance));
977 BatchCompileWasmFunctions(wasmModule, 5, 20);
978 BatchCompileWasmFunctions(wasmModule, 400, 420);
979 BatchCompileWasmFunctions(wasmModule, 1320, 1333);
980 auto exports = GetInstanceExports(instance);
981 CHECK(jsvm::IsObject(exports));
982 }
983 #else
984 static void GetLastErrorAndClean(JSVM_Env env)
985 {
986 JSVM_Value result = nullptr;
987 OH_JSVM_GetAndClearLastException(env, &result);
988 }
989
990 // test for Wasm Is Wasm Module Object
991 TEST(Wasm_IsWasmModuleObject)
992 {
993 auto number = jsvm::Run("42");
994 CHECK(!jsvm::IsWasmModuleObject(number));
995 CHECK(!jsvm::IsWasmModuleObject(jsvm::Undefined()));
996 CHECK(!jsvm::IsWasmModuleObject(jsvm::Null()));
997 CHECK(!jsvm::IsWasmModuleObject(jsvm::Str("hello")));
998 }
999
1000 // test for Wasm Compile Wasm
1001 TEST(Wasm_CompileWasmModule)
1002 {
1003 uint8_t* buffer = new uint8_t[2];
1004 buffer[0] = 0x01;
1005 buffer[1] = 0x02;
1006 JSVM_Value wasmModule = nullptr;
1007 JSVM_Status status = OH_JSVM_CompileWasmModule(jsvm_env, buffer, 2, NULL, 0, NULL, &wasmModule);
1008 delete[] buffer;
1009 CHECK(status == JSVM_JIT_MODE_EXPECTED);
1010 GetLastErrorAndClean(jsvm_env);
1011 }
1012
1013 // test for Wasm Compile Function
1014 TEST(Wasm_CompileWasmFunction)
1015 {
1016 JSVM_Value wasmModule = nullptr;
1017 JSVM_Status status = OH_JSVM_CompileWasmFunction(jsvm_env, wasmModule, 0, JSVM_WASM_OPT_HIGH);
1018 CHECK(status == JSVM_JIT_MODE_EXPECTED);
1019 GetLastErrorAndClean(jsvm_env);
1020 }
1021
1022 // test for Wasm Create Cache
1023 TEST(Wasm_CreateWasmCache)
1024 {
1025 const uint8_t *cacheData = nullptr;
1026 size_t cacheSize = 0;
1027 JSVM_Value wasmModule = nullptr;
1028 JSVM_Status status = OH_JSVM_CreateWasmCache(jsvm_env, wasmModule, &cacheData, &cacheSize);
1029 CHECK(status == JSVM_JIT_MODE_EXPECTED);
1030 GetLastErrorAndClean(jsvm_env);
1031 }
1032
1033 // test for Wasm Release Cache
1034 TEST(Wasm_ReleaseWasmCache)
1035 {
1036 uint8_t* cacheData = new uint8_t[2];
1037 cacheData[0] = 0x01;
1038 cacheData[1] = 0x02;
1039 JSVM_Status status = OH_JSVM_ReleaseCache(jsvm_env, cacheData, JSVM_CACHE_TYPE_WASM);
1040 CHECK(status == JSVM_OK);
1041 }
1042 #endif // JSVM_JITLESS
1043 #endif // TEST_WASM
1044