• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 
16 #include "quickjs_native_engine.h"
17 
18 #include <js_native_api.h>
19 
20 #include "native_engine/native_engine.h"
21 #include "native_engine/native_property.h"
22 #include "native_value/quickjs_native_array.h"
23 #include "native_value/quickjs_native_array_buffer.h"
24 #include "native_value/quickjs_native_big_int.h"
25 #include "native_value/quickjs_native_boolean.h"
26 #include "native_value/quickjs_native_buffer.h"
27 #include "native_value/quickjs_native_data_view.h"
28 #include "native_value/quickjs_native_date.h"
29 #include "native_value/quickjs_native_external.h"
30 #include "native_value/quickjs_native_function.h"
31 #include "native_value/quickjs_native_number.h"
32 #include "native_value/quickjs_native_object.h"
33 #include "native_value/quickjs_native_string.h"
34 #include "native_value/quickjs_native_typed_array.h"
35 #include "quickjs_native_deferred.h"
36 #include "quickjs_native_reference.h"
37 #include "securec.h"
38 #include "utils/assert.h"
39 #include "utils/log.h"
40 static const int JS_WRITE_OBJ = (1 << 2) | (1 << 3);
41 static const int JS_ATOM_MESSAGE = 51;
42 
QuickJSNativeEngine(JSRuntime * runtime,JSContext * context,void * jsEngine)43 QuickJSNativeEngine::QuickJSNativeEngine(JSRuntime* runtime, JSContext* context, void* jsEngine)
44     : NativeEngine(jsEngine)
45 {
46     runtime_ = runtime;
47     context_ = context;
48 
49     AddIntrinsicBaseClass(context_);
50     AddIntrinsicExternal(context_);
51 
52     JSValue jsGlobal = JS_GetGlobalObject(context_);
53     JSValue jsNativeEngine = (JSValue)JS_MKPTR(JS_TAG_INT, this);
54     JSValue jsRequireInternal = JS_NewCFunctionData(
55         context_,
56         [](JSContext* ctx, JSValueConst thisVal, int argc, JSValueConst* argv, int magic,
57             JSValue* funcData) -> JSValue {
58             JSValue result = JS_UNDEFINED;
59 
60             QuickJSNativeEngine* that = (QuickJSNativeEngine*)JS_VALUE_GET_PTR(funcData[0]);
61 
62             const char* moduleName = JS_ToCString(that->GetContext(), argv[0]);
63 
64             if (moduleName == nullptr || strlen(moduleName) == 0) {
65                 HILOG_ERROR("moduleName is nullptr or length is 0");
66                 return result;
67             }
68 
69             NativeModuleManager* moduleManager = that->GetModuleManager();
70             NativeModule* module = moduleManager->LoadNativeModule(moduleName, nullptr, false, true);
71 
72             if (module != nullptr && module->registerCallback != nullptr) {
73                 NativeValue* value = new QuickJSNativeObject(that);
74                 if (value != nullptr) {
75                     module->registerCallback(that, value);
76                     result = JS_DupValue(that->GetContext(), *value);
77                 }
78             }
79             JS_FreeCString(that->GetContext(), moduleName);
80             return result;
81         },
82         0, 0, 1, &jsNativeEngine);
83 
84     JSValue jsRequire = JS_NewCFunctionData(
85         context_,
86         [](JSContext* ctx, JSValueConst thisVal, int argc, JSValueConst* argv, int magic,
87             JSValue* funcData) -> JSValue {
88             JSValue result = JS_UNDEFINED;
89 
90             QuickJSNativeEngine* that = (QuickJSNativeEngine*)JS_VALUE_GET_PTR(funcData[0]);
91             const char* moduleName = JS_ToCString(that->GetContext(), argv[0]);
92             if (moduleName == nullptr || strlen(moduleName) == 0) {
93                 HILOG_ERROR("moduleName is nullptr or length is 0");
94                 return result;
95             }
96 
97             bool isAppModule = false;
98             if (argc == 2) {
99                 int ret = JS_ToBool(that->GetContext(), argv[1]);
100                 if (ret != -1) {
101                     isAppModule = ret;
102                 }
103             }
104             NativeModuleManager* moduleManager = that->GetModuleManager();
105             NativeModule* module = moduleManager->LoadNativeModule(moduleName, nullptr, isAppModule);
106 
107             if (module != nullptr) {
108                 if (module->jsCode != nullptr) {
109                     HILOG_INFO("load js code");
110                     NativeValue* script = that->CreateString(module->jsCode, module->jsCodeLen);
111                     NativeValue* exportObject = that->LoadModule(script, "testjsnapi.js");
112                     if (exportObject == nullptr) {
113                         HILOG_ERROR("load module failed");
114                         return result;
115                     }
116                     result = JS_DupValue(that->GetContext(), *exportObject);
117                     HILOG_ERROR("load module succ");
118                 } else if (module->registerCallback != nullptr) {
119                     HILOG_INFO("load napi module");
120                     NativeValue* value = new QuickJSNativeObject(that);
121                     module->registerCallback(that, value);
122                     result = JS_DupValue(that->GetContext(), *value);
123                 } else {
124                     HILOG_ERROR("init module failed");
125                 }
126             }
127             JS_FreeCString(that->GetContext(), moduleName);
128             return result;
129         },
130         0, 0, 1, &jsNativeEngine);
131 
132     JS_SetPropertyStr(context_, jsGlobal, "requireInternal", jsRequireInternal);
133 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
134     JS_SetPropertyStr(context_, jsGlobal, "requireNapi", jsRequire);
135 #else
136     JS_SetPropertyStr(context_, jsGlobal, "requireNapiPreview", jsRequire);
137 #endif
138     JS_FreeValue(context_, jsGlobal);
139     // need to call init of base class.
140     Init();
141 }
142 
~QuickJSNativeEngine()143 QuickJSNativeEngine::~QuickJSNativeEngine()
144 {
145     // need to call deinit before base class.
146     Deinit();
147 }
148 
GetModuleFromName(const std::string & moduleName,bool isAppModule,const std::string & id,const std::string & param,const std::string & instanceName,void ** instance)149 JSValue QuickJSNativeEngine::GetModuleFromName(
150     const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
151     const std::string& instanceName, void** instance)
152 {
153     JSValue exports = JS_UNDEFINED;
154     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
155     NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule);
156     if (module != nullptr) {
157         NativeValue* idValue = new QuickJSNativeString(this, id.c_str(), id.size());
158         NativeValue* paramValue = new QuickJSNativeString(this, param.c_str(), param.size());
159         NativeValue* exportObject = new QuickJSNativeObject(this);
160 
161         NativePropertyDescriptor idProperty, paramProperty;
162         idProperty.utf8name = "id";
163         idProperty.value = idValue;
164         paramProperty.utf8name = "param";
165         paramProperty.value = paramValue;
166         QuickJSNativeObject* exportObj = reinterpret_cast<QuickJSNativeObject*>(exportObject);
167         exportObj->DefineProperty(idProperty);
168         exportObj->DefineProperty(paramProperty);
169         module->registerCallback(this, exportObject);
170 
171         napi_value nExport = reinterpret_cast<napi_value>(exportObject);
172         napi_value exportInstance = nullptr;
173         napi_status status =
174             napi_get_named_property(reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
175         if (status != napi_ok) {
176             HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
177         }
178 
179         status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
180         if (status != napi_ok) {
181             HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
182         }
183 
184         exports = *exportObject;
185     }
186     return exports;
187 }
188 
LoadModuleByName(const std::string & moduleName,bool isAppModule,const std::string & param,const std::string & instanceName,void * instance)189 JSValue QuickJSNativeEngine::LoadModuleByName(
190     const std::string& moduleName, bool isAppModule, const std::string& param,
191     const std::string& instanceName, void* instance)
192 {
193     JSValue exports = JS_UNDEFINED;
194     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
195     NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule);
196     if (module != nullptr) {
197         NativeValue* exportObject = new QuickJSNativeObject(this);
198         QuickJSNativeObject* exportObj = reinterpret_cast<QuickJSNativeObject*>(exportObject);
199 
200         NativePropertyDescriptor paramProperty, instanceProperty;
201 
202         NativeValue* paramValue = new QuickJSNativeString(this, param.c_str(), param.size());
203         paramProperty.utf8name = "param";
204         paramProperty.value = paramValue;
205 
206         auto instanceValue = new QuickJSNativeObject(this);
207         instanceValue->SetNativePointer(instance, nullptr, nullptr);
208         instanceProperty.utf8name = instanceName.c_str();
209         instanceProperty.value = instanceValue;
210 
211         exportObj->DefineProperty(paramProperty);
212         exportObj->DefineProperty(instanceProperty);
213 
214         module->registerCallback(this, exportObject);
215         exports = JS_DupValue(GetContext(), *exportObject);
216     }
217     return exports;
218 }
219 
GetRuntime()220 JSRuntime* QuickJSNativeEngine::GetRuntime()
221 {
222     return runtime_;
223 }
224 
GetContext()225 JSContext* QuickJSNativeEngine::GetContext()
226 {
227     return context_;
228 }
229 
Loop(LoopMode mode,bool needSync)230 void QuickJSNativeEngine::Loop(LoopMode mode, bool needSync)
231 {
232     JSContext* context = nullptr;
233     NativeEngine::Loop(mode, needSync);
234     int err = JS_ExecutePendingJob(runtime_, &context);
235     if (err < 0) {
236         js_std_dump_error(context);
237     }
238 }
239 
GetGlobal()240 NativeValue* QuickJSNativeEngine::GetGlobal()
241 {
242     JSValue value = JS_GetGlobalObject(context_);
243     return new QuickJSNativeObject(this, value);
244 }
245 
CreateNull()246 NativeValue* QuickJSNativeEngine::CreateNull()
247 {
248     return new QuickJSNativeValue(this, JS_NULL);
249 }
250 
CreateUndefined()251 NativeValue* QuickJSNativeEngine::CreateUndefined()
252 {
253     return new QuickJSNativeValue(this, JS_UNDEFINED);
254 }
255 
CreateBoolean(bool value)256 NativeValue* QuickJSNativeEngine::CreateBoolean(bool value)
257 {
258     return new QuickJSNativeBoolean(this, value);
259 }
260 
CreateNumber(int32_t value)261 NativeValue* QuickJSNativeEngine::CreateNumber(int32_t value)
262 {
263     return new QuickJSNativeNumber(this, value);
264 }
265 
CreateNumber(uint32_t value)266 NativeValue* QuickJSNativeEngine::CreateNumber(uint32_t value)
267 {
268     return new QuickJSNativeNumber(this, value);
269 }
270 
CreateNumber(int64_t value)271 NativeValue* QuickJSNativeEngine::CreateNumber(int64_t value)
272 {
273     return new QuickJSNativeNumber(this, value);
274 }
275 
CreateNumber(double value)276 NativeValue* QuickJSNativeEngine::CreateNumber(double value)
277 {
278     return new QuickJSNativeNumber(this, value);
279 }
280 
CreateBigInt(int64_t value)281 NativeValue* QuickJSNativeEngine::CreateBigInt(int64_t value)
282 {
283     return new QuickJSNativeBigInt(this, value);
284 }
285 
CreateBigInt(uint64_t value)286 NativeValue* QuickJSNativeEngine::CreateBigInt(uint64_t value)
287 {
288     return new QuickJSNativeBigInt(this, value, true);
289 }
290 
CreateString(const char * value,size_t length)291 NativeValue* QuickJSNativeEngine::CreateString(const char* value, size_t length)
292 {
293     return new QuickJSNativeString(this, value, length);
294 }
295 
CreateString16(const char16_t * value,size_t length)296 NativeValue* QuickJSNativeEngine::CreateString16(const char16_t* value, size_t length)
297 {
298     return new QuickJSNativeString(this, value, length);
299 }
300 
CreateSymbol(NativeValue * value)301 NativeValue* QuickJSNativeEngine::CreateSymbol(NativeValue* value)
302 {
303     JSValue symbol = { 0 };
304 
305     JSValue global = JS_GetGlobalObject(context_);
306     JSValue symbolCotr = JS_GetPropertyStr(context_, global, "Symbol");
307 
308     JSValue jsValue = *value;
309 
310     symbol = JS_Call(context_, symbolCotr, global, 1, &jsValue);
311 
312     JS_FreeValue(context_, symbolCotr);
313     JS_FreeValue(context_, global);
314     js_std_loop(context_);
315 
316     return new QuickJSNativeValue(this, symbol);
317 }
318 
CreateFunction(const char * name,size_t length,NativeCallback cb,void * value)319 NativeValue* QuickJSNativeEngine::CreateFunction(const char* name, size_t length, NativeCallback cb, void* value)
320 {
321     return new QuickJSNativeFunction(this, name, cb, value);
322 }
323 
CreateExternal(void * value,NativeFinalize callback,void * hint)324 NativeValue* QuickJSNativeEngine::CreateExternal(void* value, NativeFinalize callback, void* hint)
325 {
326     return new QuickJSNativeExternal(this, value, callback, hint);
327 }
328 
CreateObject()329 NativeValue* QuickJSNativeEngine::CreateObject()
330 {
331     return new QuickJSNativeObject(this);
332 }
333 
CreateArrayBuffer(void ** value,size_t length)334 NativeValue* QuickJSNativeEngine::CreateArrayBuffer(void** value, size_t length)
335 {
336     return new QuickJSNativeArrayBuffer(this, (uint8_t**)value, length);
337 }
338 
CreateArrayBufferExternal(void * value,size_t length,NativeFinalize cb,void * hint)339 NativeValue* QuickJSNativeEngine::CreateArrayBufferExternal(void* value, size_t length, NativeFinalize cb, void* hint)
340 {
341     return new QuickJSNativeArrayBuffer(this, (uint8_t*)value, length, cb, hint);
342 }
343 
CreateArray(size_t length)344 NativeValue* QuickJSNativeEngine::CreateArray(size_t length)
345 {
346     return new QuickJSNativeArray(this, length);
347 }
348 
CreateDataView(NativeValue * value,size_t length,size_t offset)349 NativeValue* QuickJSNativeEngine::CreateDataView(NativeValue* value, size_t length, size_t offset)
350 {
351     return new QuickJSNativeDataView(this, value, length, offset);
352 }
353 
CreateTypedArray(NativeTypedArrayType type,NativeValue * value,size_t length,size_t offset)354 NativeValue* QuickJSNativeEngine::CreateTypedArray(NativeTypedArrayType type,
355                                                    NativeValue* value,
356                                                    size_t length,
357                                                    size_t offset)
358 {
359     return new QuickJSNativeTypedArray(this, type, value, length, offset);
360 }
361 
CreatePromise(NativeDeferred ** deferred)362 NativeValue* QuickJSNativeEngine::CreatePromise(NativeDeferred** deferred)
363 {
364     JSValue promise = { 0 };
365     JSValue resolvingFuncs[2] = { 0 };
366     promise = JS_NewPromiseCapability(context_, resolvingFuncs);
367     *deferred = new QuickJSNativeDeferred(this, resolvingFuncs);
368     return new QuickJSNativeValue(this, promise);
369 }
370 
CreateError(NativeValue * code,NativeValue * message)371 NativeValue* QuickJSNativeEngine::CreateError(NativeValue* code, NativeValue* message)
372 {
373     JSValue error = JS_NewError(context_);
374     if (code) {
375         JS_SetPropertyStr(context_, error, "code", JS_DupValue(context_, *code));
376     }
377     if (message) {
378         JS_SetPropertyStr(context_, error, "message", JS_DupValue(context_, *message));
379     }
380 
381     return new QuickJSNativeObject(this, error);
382 }
383 
CreateInstance(NativeValue * constructor,NativeValue * const * argv,size_t argc)384 NativeValue* QuickJSNativeEngine::CreateInstance(NativeValue* constructor, NativeValue* const* argv, size_t argc)
385 {
386     JSValue result = JS_UNDEFINED;
387     JSValue* params = nullptr;
388     if (argc > 0) {
389         params = new JSValue[argc];
390         for (size_t i = 0; i < argc && params != nullptr; i++) {
391             params[i] = *argv[i];
392         }
393     }
394     result = JS_CallConstructor(context_, *constructor, argc, params);
395     if (params != nullptr) {
396         delete[] params;
397     }
398     return QuickJSNativeEngine::JSValueToNativeValue(this, result);
399 }
400 
CreateReference(NativeValue * value,uint32_t initialRefcount,NativeFinalize callback,void * data,void * hint)401 NativeReference* QuickJSNativeEngine::CreateReference(NativeValue* value, uint32_t initialRefcount,
402     NativeFinalize callback, void* data, void* hint)
403 {
404     return new QuickJSNativeReference(this, value, initialRefcount, callback, data, hint);
405 }
406 
CallFunction(NativeValue * thisVar,NativeValue * function,NativeValue * const * argv,size_t argc)407 NativeValue* QuickJSNativeEngine::CallFunction(NativeValue* thisVar,
408                                                NativeValue* function,
409                                                NativeValue* const* argv,
410                                                size_t argc)
411 {
412     JSValue result = JS_UNDEFINED;
413 
414     if (function == nullptr) {
415         return new QuickJSNativeValue(this, JS_UNDEFINED);
416     }
417 
418     NativeScope* scope = scopeManager_->Open();
419     if (scope == nullptr) {
420         HILOG_ERROR("Open scope failed");
421         return new QuickJSNativeValue(this, JS_UNDEFINED);
422     }
423 
424     JSValue* args = nullptr;
425     if (argc > 0) {
426         args = new JSValue[argc];
427         for (size_t i = 0; i < argc && args != nullptr; i++) {
428             if (argv[i] != nullptr) {
429                 args[i] = *argv[i];
430             } else {
431                 args[i] = JS_UNDEFINED;
432             }
433         }
434     }
435 
436     result = JS_Call(context_, *function, (thisVar != nullptr) ? (JSValue)*thisVar : JS_UNDEFINED, argc, args);
437     js_std_loop(context_);
438     JS_DupValue(context_, result);
439 
440     if (args != nullptr) {
441         delete[] args;
442     }
443 
444     scopeManager_->Close(scope);
445 
446     if (JS_IsError(context_, result) || JS_IsException(result)) {
447         return nullptr;
448     }
449 
450     return JSValueToNativeValue(this, result);
451 }
452 
RunScript(NativeValue * script)453 NativeValue* QuickJSNativeEngine::RunScript(NativeValue* script)
454 {
455     JSValue result;
456     const char* cScript = JS_ToCString(context_, *script);
457     result = JS_Eval(context_, cScript, strlen(cScript), "<input>", JS_EVAL_TYPE_GLOBAL);
458     JS_FreeCString(context_, cScript);
459     if (JS_IsError(context_, result) || JS_IsException(result)) {
460         return nullptr;
461     }
462     js_std_loop(context_);
463 
464     return JSValueToNativeValue(this, result);
465 }
466 
SetPackagePath(const std::string & packagePath)467 void QuickJSNativeEngine::SetPackagePath(const std::string& packagePath)
468 {
469     auto moduleManager = NativeModuleManager::GetInstance();
470     if (moduleManager && !packagePath.empty()) {
471         moduleManager->SetAppLibPath(packagePath.c_str());
472     }
473 }
474 
RunBufferScript(std::vector<uint8_t> & buffer)475 NativeValue* QuickJSNativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
476 {
477     JSValue result =
478         JS_Eval(context_, reinterpret_cast<char*>(buffer.data()), buffer.size(), "<input>", JS_EVAL_TYPE_GLOBAL);
479     if (JS_IsError(context_, result) || JS_IsException(result)) {
480         return nullptr;
481     }
482     js_std_loop(context_);
483     return JSValueToNativeValue(this, result);
484 }
485 
RunActor(std::vector<uint8_t> & buffer,const char * descriptor)486 NativeValue* QuickJSNativeEngine::RunActor(std::vector<uint8_t>& buffer, const char *descriptor)
487 {
488     return RunBufferScript(buffer);
489 }
490 
LoadModule(NativeValue * str,const std::string & fileName)491 NativeValue* QuickJSNativeEngine::LoadModule(NativeValue* str, const std::string& fileName)
492 {
493     if (str == nullptr || fileName.empty()) {
494         HILOG_ERROR("moduleName is nullptr or source code length is 0");
495         return nullptr;
496     }
497 
498     JS_SetModuleLoaderFunc(runtime_, nullptr, js_module_loader, nullptr);
499     const char* moduleSource = JS_ToCString(context_, *str);
500     size_t len = strlen(moduleSource);
501     int flags = JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY;
502     JSValue moduleVal = JS_Eval(context_, moduleSource, len, fileName.c_str(), flags);
503     if (JS_IsException(moduleVal)) {
504         HILOG_ERROR("Eval source code exception");
505         JS_FreeCString(context_, moduleSource);
506         return nullptr;
507     }
508 
509     JSValue evalRes = JS_EvalFunction(context_, moduleVal);
510     if (JS_IsException(evalRes)) {
511         HILOG_ERROR("An exception occurred during Eval module");
512     }
513 
514     JSValue ns = JS_GetNameSpace(context_, moduleVal);
515     JSValue result = JS_GetPropertyStr(context_, ns, "default");
516     JS_FreeValue(context_, ns);
517     JS_FreeValue(context_, evalRes);
518     JS_FreeCString(context_, moduleSource);
519     js_std_loop(context_);
520     return JSValueToNativeValue(this, result);
521 }
522 
DefineClass(const char * name,NativeCallback callback,void * data,const NativePropertyDescriptor * properties,size_t length)523 NativeValue* QuickJSNativeEngine::DefineClass(const char* name,
524                                               NativeCallback callback,
525                                               void* data,
526                                               const NativePropertyDescriptor* properties,
527                                               size_t length)
528 {
529     NativeFunctionInfo* functionInfo = new NativeFunctionInfo();
530     if (functionInfo == nullptr) {
531         HILOG_ERROR("new NativeFunctionInfo failed");
532         return nullptr;
533     }
534     functionInfo->engine = this;
535     functionInfo->data = data;
536     functionInfo->callback = callback;
537 
538     JSValue classConstructor = JS_NewCFunction2(
539         context_,
540         [](JSContext* ctx, JSValueConst newTarget, int argc, JSValueConst* argv) -> JSValue {
541             auto callbackInfo = new NativeCallbackInfo();
542             if (callbackInfo == nullptr) {
543                 HILOG_ERROR("callbackInfo is nullptr");
544                 return JS_UNDEFINED;
545             }
546             JSValue prototype = JS_GetPropertyStr(ctx, newTarget, "prototype");
547             JSValue classContext = JS_GetPropertyStr(ctx, newTarget, "_classContext");
548 
549             auto functionInfo = (NativeFunctionInfo*)JS_ExternalToNativeObject(ctx, classContext);
550             if (functionInfo == nullptr) {
551                 HILOG_ERROR("functionInfo is nullptr");
552                 return JS_UNDEFINED;
553             }
554 
555             QuickJSNativeEngine* engine = (QuickJSNativeEngine*)functionInfo->engine;
556             NativeScopeManager* scopeManager = engine->GetScopeManager();
557             if (scopeManager == nullptr) {
558                 HILOG_ERROR("scopeManager is nullptr");
559                 return JS_UNDEFINED;
560             }
561 
562             NativeScope* scope = scopeManager->Open();
563             if (scope == nullptr) {
564                 HILOG_ERROR("scope is nullptr");
565                 delete callbackInfo;
566                 return JS_UNDEFINED;
567             }
568 
569             callbackInfo->argc = argc;
570             callbackInfo->argv = nullptr;
571             callbackInfo->function = JSValueToNativeValue(engine, JS_DupValue(ctx, newTarget));
572             callbackInfo->functionInfo = functionInfo;
573             callbackInfo->thisVar =
574                 JSValueToNativeValue(engine, JS_NewObjectProtoClass(ctx, prototype, GetBaseClassID()));
575 
576             if (callbackInfo->argc > 0) {
577                 callbackInfo->argv = new NativeValue*[argc];
578                 for (size_t i = 0; i < callbackInfo->argc && callbackInfo->argv != nullptr; i++) {
579                     callbackInfo->argv[i] = JSValueToNativeValue(engine, JS_DupValue(ctx, argv[i]));
580                 }
581             }
582 
583             NativeValue* value = functionInfo->callback(engine, callbackInfo);
584 
585             if (callbackInfo != nullptr) {
586                 delete []callbackInfo->argv;
587             }
588 
589             JSValue result = JS_UNDEFINED;
590             if (value != nullptr) {
591                 result = JS_DupValue(ctx, *value);
592             } else if (engine->IsExceptionPending()) {
593                 NativeValue* error = engine->GetAndClearLastException();
594                 if (error != nullptr) {
595                     result = JS_DupValue(ctx, *error);
596                 }
597             }
598 
599             delete callbackInfo;
600             scopeManager->Close(scope);
601 
602             return result;
603         },
604         name, 0, JS_CFUNC_constructor_or_func, 0);
605     JSValue proto = JS_NewObject(context_);
606 
607     QuickJSNativeObject* nativeClass = new QuickJSNativeObject(this, JS_DupValue(context_, classConstructor));
608     if (nativeClass == nullptr) {
609         delete functionInfo;
610         return nullptr;
611     }
612 
613     QuickJSNativeObject* nativeClassProto = new QuickJSNativeObject(this, proto);
614     if (nativeClassProto == nullptr) {
615         delete functionInfo;
616         delete nativeClass;
617         return nullptr;
618     }
619 
620     for (size_t i = 0; i < length; i++) {
621         if (properties[i].attributes & NATIVE_STATIC) {
622             nativeClass->DefineProperty(properties[i]);
623         } else {
624             nativeClassProto->DefineProperty(properties[i]);
625         }
626     }
627 
628     JS_DefinePropertyValueStr(context_, *nativeClass, "prototype", JS_DupValue(context_, *nativeClassProto), 0);
629 
630     JSValue classContext = JS_NewExternal(
631         context_, functionInfo,
632         [](JSContext* ctx, void* data, void* hint) {
633             auto info = (NativeFunctionInfo*)data;
634             HILOG_INFO("_classContext Destroy");
635             if (info != nullptr) {
636                 delete info;
637             }
638         },
639         nullptr);
640     JS_DefinePropertyValueStr(context_, *nativeClass, "_classContext", classContext, 0);
641 
642     JS_DefinePropertyValueStr(context_, *nativeClassProto, "constructor", JS_DupValue(context_, *nativeClass),
643         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
644 
645     return nativeClass;
646 }
647 
Throw(NativeValue * error)648 bool QuickJSNativeEngine::Throw(NativeValue* error)
649 {
650     JS_Throw(context_, *error);
651     this->lastException_ = error;
652     return true;
653 }
654 
Throw(NativeErrorType type,const char * code,const char * message)655 bool QuickJSNativeEngine::Throw(NativeErrorType type, const char* code, const char* message)
656 {
657     JSValue error;
658     switch (type) {
659         case NativeErrorType::NATIVE_TYPE_ERROR:
660             error = JS_ThrowTypeError(context_, "code: %s, message: %s\n", code, message);
661             break;
662         case NativeErrorType::NATIVE_RANGE_ERROR:
663             error = JS_ThrowRangeError(context_, "code: %s, message: %s\n", code, message);
664             break;
665         default:
666             error = JS_ThrowInternalError(context_, "code: %s, message: %s\n", code, message);
667     }
668     this->lastException_ = new QuickJSNativeValue(this, error);
669     return true;
670 }
671 
JSValueToNativeValue(QuickJSNativeEngine * engine,JSValue value)672 NativeValue* QuickJSNativeEngine::JSValueToNativeValue(QuickJSNativeEngine* engine, JSValue value)
673 {
674     NativeValue* result = nullptr;
675     int tag = JS_VALUE_GET_NORM_TAG(value);
676     switch (tag) {
677         case JS_TAG_BIG_INT:
678             result = new QuickJSNativeBigInt(engine, value);
679             break;
680         case JS_TAG_BIG_FLOAT:
681             result = new QuickJSNativeObject(engine, value);
682             break;
683         case JS_TAG_SYMBOL:
684             result = new QuickJSNativeValue(engine, value);
685             break;
686         case JS_TAG_STRING:
687             result = new QuickJSNativeString(engine, value);
688             break;
689         case JS_TAG_OBJECT:
690             if (JS_IsArray(engine->GetContext(), value)) {
691                 result = new QuickJSNativeArray(engine, value);
692             } else if (JS_IsError(engine->GetContext(), value)) {
693                 result = new QuickJSNativeValue(engine, value);
694             } else if (JS_IsPromise(engine->GetContext(), value)) {
695                 result = new QuickJSNativeValue(engine, value);
696             } else if (JS_IsArrayBuffer(engine->GetContext(), value)) {
697                 result = new QuickJSNativeArrayBuffer(engine, value);
698             } else if (JS_IsBuffer(engine->GetContext(), value)) {
699                 result = new QuickJSNativeBuffer(engine, value);
700             } else if (JS_IsDataView(engine->GetContext(), value)) {
701                 result = new QuickJSNativeDataView(engine, value);
702             } else if (JS_IsTypedArray(engine->GetContext(), value)) {
703                 result = new QuickJSNativeTypedArray(engine, value);
704             } else if (JS_IsExternal(engine->GetContext(), value)) {
705                 result = new QuickJSNativeExternal(engine, value);
706             } else if (JS_IsFunction(engine->GetContext(), value)) {
707                 result = new QuickJSNativeFunction(engine, value);
708             } else if (JS_IsDate(engine->GetContext(), value)) {
709                 result = new QuickJSNativeDate(engine, value);
710             } else {
711                 result = new QuickJSNativeObject(engine, value);
712             }
713             break;
714         case JS_TAG_BOOL:
715             result = new QuickJSNativeBoolean(engine, value);
716             break;
717         case JS_TAG_NULL:
718         case JS_TAG_UNDEFINED:
719         case JS_TAG_UNINITIALIZED:
720         case JS_TAG_CATCH_OFFSET:
721         case JS_TAG_EXCEPTION:
722             result = new QuickJSNativeValue(engine, value);
723             break;
724         case JS_TAG_INT:
725         case JS_TAG_FLOAT64:
726             result = new QuickJSNativeNumber(engine, value);
727             break;
728         default:
729             HILOG_DEBUG("JS_VALUE_GET_NORM_TAG %{public}d", tag);
730     }
731     return result;
732 }
733 
CreateRuntimeFunc(NativeEngine * engine,void * jsEngine)734 NativeEngine* QuickJSNativeEngine::CreateRuntimeFunc(NativeEngine* engine, void* jsEngine)
735 {
736     JSRuntime* runtime = JS_NewRuntime();
737     JSContext* context = JS_NewContext(runtime);
738 
739     QuickJSNativeEngine *qjsEngine = new QuickJSNativeEngine(runtime, context, jsEngine);
740 
741     // init callback
742     qjsEngine->RegisterWorkerFunction(engine);
743 
744     auto cleanEnv = [runtime, context]() {
745         if (context) {
746             JS_FreeContext(context);
747         }
748         if (runtime) {
749             JS_FreeRuntime(runtime);
750         }
751     };
752     qjsEngine->SetCleanEnv(cleanEnv);
753 
754     return qjsEngine;
755 }
756 
CreateRuntime()757 void* QuickJSNativeEngine::CreateRuntime()
758 {
759     return QuickJSNativeEngine::CreateRuntimeFunc(this, jsEngine_);
760 }
761 
CheckTransferList(JSValue transferList)762 bool QuickJSNativeEngine::CheckTransferList(JSValue transferList)
763 {
764     if (JS_IsUndefined(transferList)) {
765         return true;
766     }
767     if (!JS_IsArray(context_, transferList)) {
768         JS_ThrowTypeError(context_, "postMessage second parameter not a list or undefined");
769         return false;
770     }
771     int64_t len = 0;
772     js_get_length64(context_, &len, transferList);
773     for (int64_t i = 0; i < len; i++) {
774         JSValue tmp = JS_GetPropertyInt64(context_, transferList, i);
775         if (!JS_IsException(tmp)) {
776             if (!JS_IsArrayBuffer(context_, tmp)) {
777                 HILOG_ERROR("JS_ISArrayBuffer fail");
778                 return false;
779             }
780         } else {
781             HILOG_ERROR("JS_GetPropertyInt64 fail");
782             return false;
783         }
784     }
785     return true;
786 }
787 
DetachTransferList(JSValue transferList)788 bool QuickJSNativeEngine::DetachTransferList(JSValue transferList)
789 {
790     if (JS_IsUndefined(transferList)) {
791         return true;
792     }
793     int64_t len = 0;
794     js_get_length64(context_, &len, transferList);
795     for (int64_t i = 0; i < len; i++) {
796         JSValue tmp = JS_GetPropertyInt64(context_, transferList, i);
797         if (!JS_IsException(tmp)) {
798             JS_DetachArrayBuffer(context_, tmp);
799         } else {
800             return false;
801         }
802     }
803     return true;
804 }
805 
Serialize(NativeEngine * context,NativeValue * value,NativeValue * transfer)806 NativeValue* QuickJSNativeEngine::Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer)
807 {
808     if (!CheckTransferList(*transfer)) {
809         return nullptr;
810     }
811     size_t dataLen;
812     uint8_t* data = JS_WriteObject(context_, &dataLen, *value, JS_WRITE_OBJ);
813     DetachTransferList(*transfer);
814     return reinterpret_cast<NativeValue*>(new SerializeData(dataLen, data));
815 }
816 
Deserialize(NativeEngine * context,NativeValue * recorder)817 NativeValue* QuickJSNativeEngine::Deserialize(NativeEngine* context, NativeValue* recorder)
818 {
819     auto data = reinterpret_cast<SerializeData*>(recorder);
820     JSValue result = JS_ReadObject(context_, data->GetData(), data->GetSize(), JS_WRITE_OBJ);
821     return JSValueToNativeValue(this, result);
822 }
823 
DeleteSerializationData(NativeValue * value) const824 void QuickJSNativeEngine::DeleteSerializationData(NativeValue* value) const
825 {
826     SerializeData* data = reinterpret_cast<SerializeData*>(value);
827     delete data;
828 }
829 
GetExceptionForWorker() const830 ExceptionInfo* QuickJSNativeEngine::GetExceptionForWorker() const
831 {
832     JSValue exception = JS_GetCurrentException(runtime_);
833     ASSERT(JS_IsObject(exception));
834     JSValue msg;
835     ExceptionInfo* exceptionInfo = new ExceptionInfo();
836     msg = JS_GetProperty(context_, exception, JS_ATOM_MESSAGE);
837     ASSERT(JS_IsString(msg));
838     const char* exceptionStr = reinterpret_cast<char*>(JS_GetStringFromObject(msg));
839     if (exceptionStr == nullptr) {
840         delete exceptionInfo;
841         exceptionInfo = nullptr;
842         return nullptr;
843     }
844     const char* error = "Error: ";
845     int len = strlen(exceptionStr) + strlen(error) + 1;
846     if (len <= 0) {
847         return nullptr;
848     }
849     char* exceptionMessage = new char[len] { 0 };
850     if (memcpy_s(exceptionMessage, len, error, strlen(error)) != EOK) {
851         HILOG_INFO("worker:: memcpy_s error");
852         delete exceptionInfo;
853         delete[] exceptionMessage;
854         return nullptr;
855     }
856     if (memcpy_s(exceptionMessage + strlen(error), len, exceptionStr, strlen(exceptionStr)) != EOK) {
857         HILOG_INFO("worker:: memcpy_s error");
858         delete exceptionInfo;
859         delete[] exceptionMessage;
860         return nullptr;
861     }
862     exceptionInfo->message_ = exceptionMessage;
863     return exceptionInfo;
864 }
865 
ValueToNativeValue(JSValueWrapper & value)866 NativeValue* QuickJSNativeEngine::ValueToNativeValue(JSValueWrapper& value)
867 {
868     JSValue quickValue = value;
869     return JSValueToNativeValue(this, quickValue);
870 }
871 
CreateBuffer(void ** value,size_t length)872 NativeValue* QuickJSNativeEngine::CreateBuffer(void** value, size_t length)
873 {
874     return new QuickJSNativeBuffer(this, (uint8_t**)value, length);
875 }
876 
CreateBufferCopy(void ** value,size_t length,const void * data)877 NativeValue* QuickJSNativeEngine::CreateBufferCopy(void** value, size_t length, const void* data)
878 {
879     return new QuickJSNativeBuffer(this, (uint8_t**)value, length, data);
880 }
881 
CreateBufferExternal(void * value,size_t length,NativeFinalize cb,void * hint)882 NativeValue* QuickJSNativeEngine::CreateBufferExternal(void* value, size_t length, NativeFinalize cb, void* hint)
883 {
884     return new QuickJSNativeBuffer(this, (uint8_t*)value, length, cb, hint);
885 }
886 
CreateDate(double time)887 NativeValue* QuickJSNativeEngine::CreateDate(double time)
888 {
889     JSValue value = JS_StrictDate(context_, time);
890 
891     return new QuickJSNativeDate(this, value);
892 }
893 
CreateBigWords(int sign_bit,size_t word_count,const uint64_t * words)894 NativeValue* QuickJSNativeEngine::CreateBigWords(int sign_bit, size_t word_count, const uint64_t* words)
895 {
896     JSValue value = JS_CreateBigIntWords(context_, sign_bit, word_count, words);
897 
898     return new QuickJSNativeBigInt(this, value);
899 }
900 
TriggerFatalException(NativeValue * error)901 bool QuickJSNativeEngine::TriggerFatalException(NativeValue* error)
902 {
903     return false;
904 }
905 
AdjustExternalMemory(int64_t ChangeInBytes,int64_t * AdjustedValue)906 bool QuickJSNativeEngine::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue)
907 {
908     HILOG_INFO("L2: napi_adjust_external_memory not supported!");
909     return true;
910 }
911 
SetPromiseRejectCallback(NativeReference * rejectCallbackRef,NativeReference * checkCallbackRef)912 void QuickJSNativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef,
913                                                    NativeReference* checkCallbackRef) {}
914