• 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 
Global()276 JSVM_Value Global()
277 {
278     JSVM_Value js_global;
279     JSVMTEST_CALL(OH_JSVM_GetGlobal(jsvm_env, &js_global));
280     return js_global;
281 }
282 
283 // object property
GetProperty(JSVM_Value object,JSVM_Value key)284 JSVM_Value GetProperty(JSVM_Value object, JSVM_Value key)
285 {
286     JSVM_Value result;
287     JSVMTEST_CALL(OH_JSVM_GetProperty(jsvm_env, object, key, &result));
288     return result;
289 }
290 
GetProperty(JSVM_Value object,const char * name)291 JSVM_Value GetProperty(JSVM_Value object, const char *name)
292 {
293     return GetProperty(object, Str(name));
294 }
295 
SetProperty(JSVM_Value object,JSVM_Value key,JSVM_Value value)296 void SetProperty(JSVM_Value object, JSVM_Value key, JSVM_Value value)
297 {
298     JSVMTEST_CALL(OH_JSVM_SetProperty(jsvm_env, object, key, value));
299 }
300 
SetProperty(JSVM_Value object,const char * name,JSVM_Value value)301 void SetProperty(JSVM_Value object, const char *name, JSVM_Value value)
302 {
303     JSVMTEST_CALL(OH_JSVM_SetProperty(jsvm_env, object, Str(name), value));
304 }
305 
306 // Get named property with name `name` from globalThis
Global(const char * name)307 JSVM_Value Global(const char *name)
308 {
309     return GetProperty(Global(), Str(name));
310 }
311 
312 // Get property with key `key` from globalThis
Global(JSVM_Value key)313 JSVM_Value Global(JSVM_Value key)
314 {
315     return GetProperty(Global(), key);
316 }
317 
318 // Call function with normal function with empty argument list
Call(JSVM_Value func)319 JSVM_Value Call(JSVM_Value func)
320 {
321     JSVM_Value result;
322     JSVMTEST_CALL(OH_JSVM_CallFunction(jsvm_env, Undefined(), func, 0, NULL, &result));
323     return result;
324 }
325 
326 // Call function with normal function with specified argument list
Call(JSVM_Value func,JSVM_Value thisArg,std::initializer_list<JSVM_Value> args)327 JSVM_Value Call(JSVM_Value func, JSVM_Value thisArg, std::initializer_list<JSVM_Value> args)
328 {
329     JSVM_Value result;
330     int argc = args.size();
331     if (argc == 0) {
332         JSVMTEST_CALL(OH_JSVM_CallFunction(jsvm_env, thisArg, func, 0, NULL, &result));
333         return result;
334     }
335     JSVM_Value argv[argc];
336     size_t i = 0;
337     for (JSVM_Value a : args) {
338         argv[i++] = a;
339     }
340     JSVMTEST_CALL(OH_JSVM_CallFunction(jsvm_env, thisArg, func, argc, argv, &result));
341     return result;
342 }
343 
344 // Call function as constructor with empty argument list
New(JSVM_Value constructor)345 JSVM_Value New(JSVM_Value constructor)
346 {
347     JSVM_Value result;
348     JSVMTEST_CALL(OH_JSVM_NewInstance(jsvm_env, constructor, 0, NULL, &result));
349     return result;
350 }
351 
InstanceOf(JSVM_Value value,JSVM_Value constructor)352 bool InstanceOf(JSVM_Value value, JSVM_Value constructor)
353 {
354     bool result;
355     JSVMTEST_CALL(OH_JSVM_Instanceof(jsvm_env, value, constructor, &result));
356     return result;
357 }
358 
IsNull(JSVM_Value value)359 bool IsNull(JSVM_Value value)
360 {
361     bool result;
362     JSVMTEST_CALL(OH_JSVM_IsNull(jsvm_env, value, &result));
363     return result;
364 }
365 
IsUndefined(JSVM_Value value)366 bool IsUndefined(JSVM_Value value)
367 {
368     bool result;
369     JSVMTEST_CALL(OH_JSVM_IsUndefined(jsvm_env, value, &result));
370     return result;
371 }
372 
IsNullOrUndefined(JSVM_Value value)373 bool IsNullOrUndefined(JSVM_Value value)
374 {
375     bool result;
376     JSVMTEST_CALL(OH_JSVM_IsNullOrUndefined(jsvm_env, value, &result));
377     return result;
378 }
379 
IsBoolean(JSVM_Value value)380 bool IsBoolean(JSVM_Value value)
381 {
382     bool result;
383     JSVMTEST_CALL(OH_JSVM_IsBoolean(jsvm_env, value, &result));
384     return result;
385 }
386 
IsTrue(JSVM_Value value)387 bool IsTrue(JSVM_Value value)
388 {
389     return IsBoolean(value) && ToBoolean(value) == true;
390 }
391 
IsFalse(JSVM_Value value)392 bool IsFalse(JSVM_Value value)
393 {
394     return IsBoolean(value) && ToBoolean(value) == false;
395 }
396 
IsNumber(JSVM_Value value)397 bool IsNumber(JSVM_Value value)
398 {
399     bool result;
400     JSVMTEST_CALL(OH_JSVM_IsNumber(jsvm_env, value, &result));
401     return result;
402 }
403 
IsString(JSVM_Value value)404 bool IsString(JSVM_Value value)
405 {
406     bool result;
407     JSVMTEST_CALL(OH_JSVM_IsString(jsvm_env, value, &result));
408     return result;
409 }
410 
IsObject(JSVM_Value value)411 bool IsObject(JSVM_Value value)
412 {
413     bool result;
414     JSVMTEST_CALL(OH_JSVM_IsObject(jsvm_env, value, &result));
415     return result;
416 }
417 
IsBigInt(JSVM_Value value)418 bool IsBigInt(JSVM_Value value)
419 {
420     bool result;
421     JSVMTEST_CALL(OH_JSVM_IsBigInt(jsvm_env, value, &result));
422     return result;
423 }
424 
IsSymbol(JSVM_Value value)425 bool IsSymbol(JSVM_Value value)
426 {
427     bool result;
428     JSVMTEST_CALL(OH_JSVM_IsSymbol(jsvm_env, value, &result));
429     return result;
430 }
431 
IsFunction(JSVM_Value value)432 bool IsFunction(JSVM_Value value)
433 {
434     bool result;
435     JSVMTEST_CALL(OH_JSVM_IsFunction(jsvm_env, value, &result));
436     return result;
437 }
438 
IsArray(JSVM_Value value)439 bool IsArray(JSVM_Value value)
440 {
441     bool result;
442     JSVMTEST_CALL(OH_JSVM_IsArray(jsvm_env, value, &result));
443     return result;
444 }
445 
IsArraybuffer(JSVM_Value value)446 bool IsArraybuffer(JSVM_Value value)
447 {
448     bool result;
449     JSVMTEST_CALL(OH_JSVM_IsArraybuffer(jsvm_env, value, &result));
450     return result;
451 }
452 
IsPromise(JSVM_Value value)453 bool IsPromise(JSVM_Value value)
454 {
455     bool result;
456     JSVMTEST_CALL(OH_JSVM_IsPromise(jsvm_env, value, &result));
457     return result;
458 }
459 
IsWasmModuleObject(JSVM_Value value)460 bool IsWasmModuleObject(JSVM_Value value)
461 {
462     bool result;
463 #ifdef TEST_WASM
464     JSVMTEST_CALL(OH_JSVM_IsWasmModuleObject(jsvm_env, value, &result));
465 #else
466     auto Module = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Module");
467     result = jsvm::InstanceOf(value, Module);
468 #endif
469     return result;
470 }
471 
IsWebAssemblyInstance(JSVM_Value value)472 bool IsWebAssemblyInstance(JSVM_Value value)
473 {
474     auto Instance = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Instance");
475     return jsvm::InstanceOf(value, Instance);
476 }
477 
IsWebAssemblyMemory(JSVM_Value value)478 bool IsWebAssemblyMemory(JSVM_Value value)
479 {
480     auto Memory = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Memory");
481     return jsvm::InstanceOf(value, Memory);
482 }
483 
IsWebAssemblyTable(JSVM_Value value)484 bool IsWebAssemblyTable(JSVM_Value value)
485 {
486     auto Table = jsvm::GetProperty(jsvm::Global("WebAssembly"), "Table");
487     return jsvm::InstanceOf(value, Table);
488 }
489 
StringLength(JSVM_Value str)490 size_t StringLength(JSVM_Value str)
491 {
492     CHECK(IsString(str));
493     size_t length;
494     JSVMTEST_CALL(OH_JSVM_GetValueStringUtf8(jsvm_env, str, NULL, 0, &length));
495     return length;
496 }
497 
ArrayLength(JSVM_Value array)498 uint32_t ArrayLength(JSVM_Value array)
499 {
500     CHECK(IsArray(array));
501     uint32_t length;
502     JSVMTEST_CALL(OH_JSVM_GetArrayLength(jsvm_env, array, &length));
503     return length;
504 }
505 
ArrayAt(JSVM_Value array,uint32_t index)506 JSVM_Value ArrayAt(JSVM_Value array, uint32_t index)
507 {
508     JSVM_Value element;
509     JSVMTEST_CALL(OH_JSVM_GetElement(jsvm_env, array, index, &element));
510     return element;
511 }
512 
JsonParse(JSVM_Value str)513 JSVM_Value JsonParse(JSVM_Value str)
514 {
515     JSVM_Value obj;
516     JSVMTEST_CALL(OH_JSVM_JsonParse(jsvm_env, str, &obj));
517     return obj;
518 }
519 
JsonStringify(JSVM_Value obj)520 JSVM_Value JsonStringify(JSVM_Value obj)
521 {
522     JSVM_Value str;
523     JSVMTEST_CALL(OH_JSVM_JsonStringify(jsvm_env, obj, &str));
524     return str;
525 }
526 
Equals(JSVM_Value lhs,JSVM_Value rhs)527 bool Equals(JSVM_Value lhs, JSVM_Value rhs)
528 {
529     bool result;
530     JSVMTEST_CALL(OH_JSVM_Equals(jsvm_env, lhs, rhs, &result));
531     return result;
532 }
533 
StrictEquals(JSVM_Value lhs,JSVM_Value rhs)534 bool StrictEquals(JSVM_Value lhs, JSVM_Value rhs)
535 {
536     bool result;
537     JSVMTEST_CALL(OH_JSVM_StrictEquals(jsvm_env, lhs, rhs, &result));
538     return result;
539 }
540 
541 // This is a simple log function
MyConsoleLog(JSVM_Env env,JSVM_CallbackInfo info)542 JSVM_Value MyConsoleLog(JSVM_Env env, JSVM_CallbackInfo info)
543 {
544     size_t argc = 1;
545     JSVM_Value argv[1];
546     JSVMTEST_CALL(OH_JSVM_GetCbInfo(env, info, &argc, argv, NULL, NULL));
547     JSVM_Value x = argv[0];
548     std::string str = jsvm::ToString(x);
549     Print(str.c_str());
550     return jsvm::Undefined();
551 }
552 
InstallMyConsoleLog(JSVM_Env env)553 void InstallMyConsoleLog(JSVM_Env env)
554 {
555     static JSVM_CallbackStruct cb = {MyConsoleLog, NULL};
556     JSVM_Value log;
557     JSVMTEST_CALL(OH_JSVM_CreateFunction(env, "log", JSVM_AUTO_LENGTH, &cb, &log));
558     CHECK(jsvm::IsFunction(log));
559     auto console = jsvm::Global("console");
560     if (!jsvm::IsObject(console)) {
561         JSVMTEST_CALL(OH_JSVM_CreateObject(env, &console));
562         jsvm::SetProperty(jsvm::Global(), "console", console);
563     }
564     jsvm::SetProperty(console, "log", log);
565 }
566 
567 }  // namespace jsvm
568