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