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