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