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