• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "jsvm_utils.h"
16 
17 #include <cstdint>
18 #include <cstdio>
19 #include <cstring>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 #include "jsvm.h"
25 
Print(const char * str)26 void Print(const char* str)
27 {
28     printf("%s\n", str);
29 }
30 
PrintException(JSVM_Env env,JSVM_Value exception,const char * call)31 void PrintException(JSVM_Env env, JSVM_Value exception, const char* call)
32 {
33     bool isObject = false;
34     JSVM_Status status = OH_JSVM_IsObject(env, exception, &isObject);
35     ASSERT_EQ(status, JSVM_OK);
36     ASSERT_TRUE(isObject);
37 
38     JSVM_Value stack;
39     status = OH_JSVM_GetNamedProperty(env, exception, "stack", &stack);
40     ASSERT_EQ(status, JSVM_OK);
41     char stackStr[BUF_SIZE];
42     OH_JSVM_GetValueStringUtf8(env, stack, stackStr, BUF_SIZE, nullptr);
43     printf("[PrintException] exception.stack: %s\n", stackStr);
44 
45     status = OH_JSVM_GetNamedProperty(env, exception, "message", &stack);
46     ASSERT_EQ(status, JSVM_OK);
47     char messageStr[BUF_SIZE];
48     OH_JSVM_GetValueStringUtf8(env, stack, messageStr, BUF_SIZE, nullptr);
49     printf("[PrintException] exception.message: %s\n", messageStr);
50 }
51 
CheckErrorAndException(JSVM_Env env,JSVM_Status returnStatus,const char * call)52 void CheckErrorAndException(JSVM_Env env, JSVM_Status returnStatus, const char* call)
53 {
54     const JSVM_ExtendedErrorInfo* errorInfo;
55     JSVM_Status status = OH_JSVM_GetLastErrorInfo(env, &errorInfo);
56     ASSERT_EQ(status, JSVM_OK);
57     ASSERT_EQ(returnStatus, errorInfo->errorCode);
58     bool isPending = false;
59     status = OH_JSVM_IsExceptionPending(env, &isPending);
60     ASSERT_EQ(status, JSVM_OK);
61     JSVM_Value exception;
62     status = OH_JSVM_GetAndClearLastException(env, &exception);
63     ASSERT_EQ(status, JSVM_OK);
64     bool isExceptionUndefined = false;
65     status = OH_JSVM_IsUndefined(env, exception, &isExceptionUndefined);
66     ASSERT_EQ(status, JSVM_OK);
67     bool hasException = !isExceptionUndefined;
68     if (hasException) {
69         ASSERT_TRUE(isPending);
70         ASSERT_NE(returnStatus, JSVM_OK);
71         PrintException(env, exception, call);
72         ASSERT_TRUE(false);
73     } else {
74         // no exception
75         ASSERT_FALSE(isPending);
76     }
77     ASSERT_EQ(returnStatus, JSVM_OK);
78 }
79 
80 // jsvm utils
81 namespace jsvm {
82 
Str(const char * s)83 JSVM_Value Str(const char* s)
84 {
85     JSVM_Value str;
86     JSVMTEST_CALL(OH_JSVM_CreateStringUtf8(jsvm_env, s, JSVM_AUTO_LENGTH, &str));
87     return str;
88 }
89 
Str(const std::string & stdString)90 JSVM_Value Str(const std::string& stdString)
91 {
92     return Str(stdString.c_str());
93 }
94 
Compile(JSVM_Value js_str,const uint8_t * cache,size_t size)95 JSVM_Script Compile(JSVM_Value js_str, const uint8_t* cache, size_t size)
96 {
97     JSVM_Script script;
98     JSVMTEST_CALL(OH_JSVM_CompileScript(jsvm_env, js_str, cache, size, false, nullptr, &script));
99     return script;
100 }
101 
CompileWithName(JSVM_Value js_str,const char * name)102 JSVM_Script CompileWithName(JSVM_Value js_str, const char* name)
103 {
104     JSVM_Script script;
105     JSVM_ScriptOrigin origin = {
106         .sourceMapUrl = nullptr,
107         .resourceName = name,
108     };
109     JSVMTEST_CALL(
110         OH_JSVM_CompileScriptWithOrigin(jsvm_env, js_str, NULL, JSVM_AUTO_LENGTH, false, NULL, &origin, &script));
111     return script;
112 }
113 
Compile(const char * s,const uint8_t * cache,size_t size)114 JSVM_Script Compile(const char* s, const uint8_t* cache, size_t size)
115 {
116     return Compile(Str(s), cache, size);
117 }
118 
CompileWithName(const char * s,const char * name)119 JSVM_Script CompileWithName(const char* s, const char* name)
120 {
121     return CompileWithName(Str(s), name);
122 }
123 
Run(JSVM_Script script)124 JSVM_Value Run(JSVM_Script script)
125 {
126     JSVM_Value result;
127     JSVMTEST_CALL(OH_JSVM_RunScript(jsvm_env, script, &result));
128     return result;
129 }
130 
Run(const char * s)131 JSVM_Value Run(const char* s)
132 {
133     return Run(Compile(s));
134 }
135 
ToBoolean(JSVM_Value val)136 bool ToBoolean(JSVM_Value val)
137 {
138     JSVM_Value js_boolean;
139     JSVMTEST_CALL(OH_JSVM_CoerceToBool(jsvm_env, val, &js_boolean));
140     bool res;
141     JSVMTEST_CALL(OH_JSVM_GetValueBool(jsvm_env, js_boolean, &res));
142     return res;
143 }
144 
ToNumber(JSVM_Value val)145 double ToNumber(JSVM_Value val)
146 {
147     JSVM_Value js_number;
148     JSVMTEST_CALL(OH_JSVM_CoerceToNumber(jsvm_env, val, &js_number));
149     double res;
150     JSVMTEST_CALL(OH_JSVM_GetValueDouble(jsvm_env, js_number, &res));
151     return res;
152 }
153 
ToString(JSVM_Value val)154 std::string ToString(JSVM_Value val)
155 {
156     JSVM_Value js_string;
157     JSVMTEST_CALL(OH_JSVM_CoerceToString(jsvm_env, val, &js_string));
158     size_t length = 0;
159     JSVMTEST_CALL(OH_JSVM_GetValueStringUtf8(jsvm_env, js_string, NULL, 0, &length));
160     size_t capacity = length + 1;
161     char* buffer = new char[capacity];
162     size_t copyLength = 0;
163     JSVMTEST_CALL(OH_JSVM_GetValueStringUtf8(jsvm_env, js_string, buffer, capacity, &copyLength));
164     std::string str(buffer);
165     delete[] buffer;
166     return str;
167 }
168 
True()169 JSVM_Value True()
170 {
171     JSVM_Value js_true;
172     JSVMTEST_CALL(OH_JSVM_GetBoolean(jsvm_env, true, &js_true));
173     return js_true;
174 }
175 
False()176 JSVM_Value False()
177 {
178     JSVM_Value js_false;
179     JSVMTEST_CALL(OH_JSVM_GetBoolean(jsvm_env, false, &js_false));
180     return js_false;
181 }
182 
Undefined()183 JSVM_Value Undefined()
184 {
185     JSVM_Value js_undefined;
186     JSVMTEST_CALL(OH_JSVM_GetUndefined(jsvm_env, &js_undefined));
187     return js_undefined;
188 }
189 
Null()190 JSVM_Value Null()
191 {
192     JSVM_Value js_null;
193     JSVMTEST_CALL(OH_JSVM_GetNull(jsvm_env, &js_null));
194     return js_null;
195 }
196 
Int32(int32_t v)197 JSVM_Value Int32(int32_t v)
198 {
199     JSVM_Value result;
200     JSVMTEST_CALL(OH_JSVM_CreateInt32(jsvm_env, v, &result));
201     return result;
202 }
203 
Int64(int64_t v)204 JSVM_Value Int64(int64_t v)
205 {
206     JSVM_Value result;
207     JSVMTEST_CALL(OH_JSVM_CreateInt64(jsvm_env, v, &result));
208     return result;
209 }
210 
Uint32(uint32_t v)211 JSVM_Value Uint32(uint32_t v)
212 {
213     JSVM_Value result;
214     JSVMTEST_CALL(OH_JSVM_CreateUint32(jsvm_env, v, &result));
215     return result;
216 }
217 
Double(double v)218 JSVM_Value Double(double v)
219 {
220     JSVM_Value result;
221     JSVMTEST_CALL(OH_JSVM_CreateDouble(jsvm_env, v, &result));
222     return result;
223 }
224 
Object()225 JSVM_Value Object()
226 {
227     JSVM_Value js_object;
228     JSVMTEST_CALL(OH_JSVM_CreateObject(jsvm_env, &js_object));
229     return js_object;
230 }
231 
Global()232 JSVM_Value Global()
233 {
234     JSVM_Value js_global;
235     JSVMTEST_CALL(OH_JSVM_GetGlobal(jsvm_env, &js_global));
236     return js_global;
237 }
238 
239 // object property
GetProperty(JSVM_Value object,JSVM_Value key)240 JSVM_Value GetProperty(JSVM_Value object, JSVM_Value key)
241 {
242     JSVM_Value result;
243     JSVMTEST_CALL(OH_JSVM_GetProperty(jsvm_env, object, key, &result));
244     return result;
245 }
246 
GetProperty(JSVM_Value object,const char * name)247 JSVM_Value GetProperty(JSVM_Value object, const char* name)
248 {
249     return GetProperty(object, Str(name));
250 }
251 
SetProperty(JSVM_Value object,JSVM_Value key,JSVM_Value value)252 void SetProperty(JSVM_Value object, JSVM_Value key, JSVM_Value value)
253 {
254     JSVMTEST_CALL(OH_JSVM_SetProperty(jsvm_env, object, key, value));
255 }
256 
SetProperty(JSVM_Value object,const char * name,JSVM_Value value)257 void SetProperty(JSVM_Value object, const char* name, JSVM_Value value)
258 {
259     JSVMTEST_CALL(OH_JSVM_SetProperty(jsvm_env, object, Str(name), value));
260 }
261 
262 // Get named property with name `name` from globalThis
Global(const char * name)263 JSVM_Value Global(const char* name)
264 {
265     return GetProperty(Global(), Str(name));
266 }
267 
268 // Get property with key `key` from globalThis
Global(JSVM_Value key)269 JSVM_Value Global(JSVM_Value key)
270 {
271     return GetProperty(Global(), key);
272 }
273 
274 // Call function with normal function with empty argument list
Call(JSVM_Value func)275 JSVM_Value Call(JSVM_Value func)
276 {
277     JSVM_Value result;
278     JSVMTEST_CALL(OH_JSVM_CallFunction(jsvm_env, Undefined(), func, 0, NULL, &result));
279     return result;
280 }
281 
282 // Call function with normal function with specified argument list
Call(JSVM_Value func,JSVM_Value thisArg,std::initializer_list<JSVM_Value> args)283 JSVM_Value Call(JSVM_Value func, JSVM_Value thisArg, std::initializer_list<JSVM_Value> args)
284 {
285     JSVM_Value result;
286     int argc = args.size();
287     if (argc == 0) {
288         JSVMTEST_CALL(OH_JSVM_CallFunction(jsvm_env, thisArg, func, 0, NULL, &result));
289         return result;
290     }
291     JSVM_Value argv[argc];
292     size_t i = 0;
293     for (JSVM_Value a : args) {
294         argv[i++] = a;
295     }
296     JSVMTEST_CALL(OH_JSVM_CallFunction(jsvm_env, thisArg, func, argc, argv, &result));
297     return result;
298 }
299 
300 // Call function as constructor with empty argument list
New(JSVM_Value constructor)301 JSVM_Value New(JSVM_Value constructor)
302 {
303     JSVM_Value result;
304     JSVMTEST_CALL(OH_JSVM_NewInstance(jsvm_env, constructor, 0, NULL, &result));
305     return result;
306 }
307 
InstanceOf(JSVM_Value value,JSVM_Value constructor)308 bool InstanceOf(JSVM_Value value, JSVM_Value constructor)
309 {
310     bool result;
311     JSVMTEST_CALL(OH_JSVM_Instanceof(jsvm_env, value, constructor, &result));
312     return result;
313 }
314 
IsNull(JSVM_Value value)315 bool IsNull(JSVM_Value value)
316 {
317     bool result;
318     JSVMTEST_CALL(OH_JSVM_IsNull(jsvm_env, value, &result));
319     return result;
320 }
321 
IsUndefined(JSVM_Value value)322 bool IsUndefined(JSVM_Value value)
323 {
324     bool result;
325     JSVMTEST_CALL(OH_JSVM_IsUndefined(jsvm_env, value, &result));
326     return result;
327 }
328 
IsNullOrUndefined(JSVM_Value value)329 bool IsNullOrUndefined(JSVM_Value value)
330 {
331     bool result;
332     JSVMTEST_CALL(OH_JSVM_IsNullOrUndefined(jsvm_env, value, &result));
333     return result;
334 }
335 
IsBoolean(JSVM_Value value)336 bool IsBoolean(JSVM_Value value)
337 {
338     bool result;
339     JSVMTEST_CALL(OH_JSVM_IsBoolean(jsvm_env, value, &result));
340     return result;
341 }
342 
IsTrue(JSVM_Value value)343 bool IsTrue(JSVM_Value value)
344 {
345     return IsBoolean(value) && ToBoolean(value) == true;
346 }
347 
IsFalse(JSVM_Value value)348 bool IsFalse(JSVM_Value value)
349 {
350     return IsBoolean(value) && ToBoolean(value) == false;
351 }
352 
IsNumber(JSVM_Value value)353 bool IsNumber(JSVM_Value value)
354 {
355     bool result;
356     JSVMTEST_CALL(OH_JSVM_IsNumber(jsvm_env, value, &result));
357     return result;
358 }
359 
IsString(JSVM_Value value)360 bool IsString(JSVM_Value value)
361 {
362     bool result;
363     JSVMTEST_CALL(OH_JSVM_IsString(jsvm_env, value, &result));
364     return result;
365 }
366 
IsObject(JSVM_Value value)367 bool IsObject(JSVM_Value value)
368 {
369     bool result;
370     JSVMTEST_CALL(OH_JSVM_IsObject(jsvm_env, value, &result));
371     return result;
372 }
373 
IsBigInt(JSVM_Value value)374 bool IsBigInt(JSVM_Value value)
375 {
376     bool result;
377     JSVMTEST_CALL(OH_JSVM_IsBigInt(jsvm_env, value, &result));
378     return result;
379 }
380 
IsSymbol(JSVM_Value value)381 bool IsSymbol(JSVM_Value value)
382 {
383     bool result;
384     JSVMTEST_CALL(OH_JSVM_IsSymbol(jsvm_env, value, &result));
385     return result;
386 }
387 
IsFunction(JSVM_Value value)388 bool IsFunction(JSVM_Value value)
389 {
390     bool result;
391     JSVMTEST_CALL(OH_JSVM_IsFunction(jsvm_env, value, &result));
392     return result;
393 }
394 
IsArray(JSVM_Value value)395 bool IsArray(JSVM_Value value)
396 {
397     bool result;
398     JSVMTEST_CALL(OH_JSVM_IsArray(jsvm_env, value, &result));
399     return result;
400 }
401 
IsArraybuffer(JSVM_Value value)402 bool IsArraybuffer(JSVM_Value value)
403 {
404     bool result;
405     JSVMTEST_CALL(OH_JSVM_IsArraybuffer(jsvm_env, value, &result));
406     return result;
407 }
408 
IsPromise(JSVM_Value value)409 bool IsPromise(JSVM_Value value)
410 {
411     bool result;
412     JSVMTEST_CALL(OH_JSVM_IsPromise(jsvm_env, value, &result));
413     return result;
414 }
415 
IsWasmModuleObject(JSVM_Value value)416 bool IsWasmModuleObject(JSVM_Value value)
417 {
418     bool result;
419 #ifdef TEST_WASM
420     JSVMTEST_CALL(OH_JSVM_IsWasmModuleObject(jsvm_env, value, &result));
421 #else
422     auto Module = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Module");
423     result = jsvm::InstanceOf(value, Module);
424 #endif
425     return result;
426 }
427 
IsWebAssemblyInstance(JSVM_Value value)428 bool IsWebAssemblyInstance(JSVM_Value value)
429 {
430     auto Instance = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Instance");
431     return jsvm::InstanceOf(value, Instance);
432 }
433 
IsWebAssemblyMemory(JSVM_Value value)434 bool IsWebAssemblyMemory(JSVM_Value value)
435 {
436     auto Memory = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Memory");
437     return jsvm::InstanceOf(value, Memory);
438 }
439 
IsWebAssemblyTable(JSVM_Value value)440 bool IsWebAssemblyTable(JSVM_Value value)
441 {
442     auto Table = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Table");
443     return jsvm::InstanceOf(value, Table);
444 }
445 
ArrayAt(JSVM_Value array,uint32_t index)446 JSVM_Value ArrayAt(JSVM_Value array, uint32_t index)
447 {
448     JSVM_Value element;
449     JSVMTEST_CALL(OH_JSVM_GetElement(jsvm_env, array, index, &element));
450     return element;
451 }
452 
JsonParse(JSVM_Value str)453 JSVM_Value JsonParse(JSVM_Value str)
454 {
455     JSVM_Value obj;
456     JSVMTEST_CALL(OH_JSVM_JsonParse(jsvm_env, str, &obj));
457     return obj;
458 }
459 
JsonStringify(JSVM_Value obj)460 JSVM_Value JsonStringify(JSVM_Value obj)
461 {
462     JSVM_Value str;
463     JSVMTEST_CALL(OH_JSVM_JsonStringify(jsvm_env, obj, &str));
464     return str;
465 }
466 
Equals(JSVM_Value lhs,JSVM_Value rhs)467 bool Equals(JSVM_Value lhs, JSVM_Value rhs)
468 {
469     bool result;
470     JSVMTEST_CALL(OH_JSVM_Equals(jsvm_env, lhs, rhs, &result));
471     return result;
472 }
473 
StrictEquals(JSVM_Value lhs,JSVM_Value rhs)474 bool StrictEquals(JSVM_Value lhs, JSVM_Value rhs)
475 {
476     bool result;
477     JSVMTEST_CALL(OH_JSVM_StrictEquals(jsvm_env, lhs, rhs, &result));
478     return result;
479 }
480 
481 // This is a simple log function
MyConsoleLog(JSVM_Env env,JSVM_CallbackInfo info)482 JSVM_Value MyConsoleLog(JSVM_Env env, JSVM_CallbackInfo info)
483 {
484     size_t argc = 1;
485     JSVM_Value argv[1];
486     JSVMTEST_CALL(OH_JSVM_GetCbInfo(env, info, &argc, argv, NULL, NULL));
487     JSVM_Value x = argv[0];
488     std::string str = jsvm::ToString(x);
489     Print(str.c_str());
490     return jsvm::Undefined();
491 }
492 
InstallMyConsoleLog(JSVM_Env env)493 void InstallMyConsoleLog(JSVM_Env env)
494 {
495     static JSVM_CallbackStruct cb = { MyConsoleLog, NULL };
496     JSVM_Value log;
497     JSVMTEST_CALL(OH_JSVM_CreateFunction(env, "log", JSVM_AUTO_LENGTH, &cb, &log));
498     ASSERT_TRUE(jsvm::IsFunction(log));
499     auto console = jsvm::Global("console");
500     if (!jsvm::IsObject(console)) {
501         JSVMTEST_CALL(OH_JSVM_CreateObject(env, &console));
502         jsvm::SetProperty(jsvm::Global(), "console", console);
503     }
504     jsvm::SetProperty(console, "log", log);
505 }
506 
TryTriggerOOM()507 void TryTriggerOOM()
508 {
509     static std::vector<JSVM_Value> arrayVec;
510     int loopCount = 10000;
511     for (int i = 0; i < loopCount; i++) {
512         JSVM_Value array;
513         JSVMTEST_CALL(OH_JSVM_CreateArrayWithLength(jsvm_env, 0xffffff, &array));
514         arrayVec.push_back(array);
515     }
516 }
517 
TryTriggerFatalError(JSVM_VM vm)518 void TryTriggerFatalError(JSVM_VM vm)
519 {
520     OH_JSVM_DestroyVM(vm);
521 }
522 
TryTriggerGC()523 void TryTriggerGC()
524 {
525     JSVMTEST_CALL(OH_JSVM_MemoryPressureNotification(jsvm_env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL));
526 }
527 } // namespace jsvm
528