From a223df67930e324f20405d9319deef586ff8d1f2 Mon Sep 17 00:00:00 2001 From: wupengyong Date: Thu, 19 Aug 2021 10:46:56 +0800 Subject: [PATCH] add quickjs napi Signed-off-by: wupengyong Change-Id: I951839ceadf741d2a8d6fee952d746f50715a8ab --- interfaces/kits/napi/native_api.h | 6 + interfaces/kits/napi/native_common.h | 5 + module_manager/native_module_manager.cpp | 24 +-- module_manager/native_module_manager.h | 11 +- native_engine/impl/quickjs/quickjs_ext.cpp | 2 +- .../impl/quickjs/quickjs_native_engine.cpp | 139 +++++++++++++++++- .../impl/quickjs/quickjs_native_engine.h | 35 +++++ .../impl/quickjs/quickjs_native_reference.cpp | 2 +- native_engine/native_api.cpp | 89 +++++++++++ native_engine/native_async_work.cpp | 47 ++++++ native_engine/native_async_work.h | 34 ++++- native_engine/native_engine.cpp | 43 ++++++ native_engine/native_engine.h | 56 ++++++- 13 files changed, 466 insertions(+), 27 deletions(-) diff --git a/interfaces/kits/napi/native_api.h b/interfaces/kits/napi/native_api.h index d1c720cdb..ee4dea417 100644 --- a/interfaces/kits/napi/native_api.h +++ b/interfaces/kits/napi/native_api.h @@ -27,5 +27,11 @@ DEPRECATED napi_status napi_get_value_string_utf16(napi_env env, size_t bufsize, size_t* result); DEPRECATED napi_status napi_adjust_external_memory(napi_env env, int64_t change_in_bytes, int64_t* adjusted_value); +napi_status napi_is_callable(napi_env env, napi_value value, bool* result); + napi_status napi_create_runtime(napi_env env, napi_env* result_env); + napi_status napi_serialize(napi_env env, napi_value object, napi_value transfer_list, napi_value* result); + napi_status napi_deserialize(napi_env env, napi_value recorder, napi_value* object); + napi_status napi_delete_serialization_data(napi_env env, napi_value value); + napi_status napi_get_exception_info_for_worker(napi_env env, napi_value obj); #endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_API_H */ diff --git a/interfaces/kits/napi/native_common.h b/interfaces/kits/napi/native_common.h index efba395e0..5fabf4e9f 100644 --- a/interfaces/kits/napi/native_common.h +++ b/interfaces/kits/napi/native_common.h @@ -74,6 +74,11 @@ (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ } +#define DECLARE_NAPI_FUNCTION_WITH_DATA(name, func, data) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, data \ + } + #define DECLARE_NAPI_STATIC_FUNCTION(name, func) \ { \ (name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr \ diff --git a/module_manager/native_module_manager.cpp b/module_manager/native_module_manager.cpp index 4445aa45e..b7317d163 100644 --- a/module_manager/native_module_manager.cpp +++ b/module_manager/native_module_manager.cpp @@ -74,7 +74,7 @@ void NativeModuleManager::Register(NativeModule* nativeModule) lastNativeModule_->next = nullptr; } -NativeModule* NativeModuleManager::LoadNativeModule(const char* moduleName, bool internal) +NativeModule* NativeModuleManager::LoadNativeModule(const char* moduleName, const char* path, bool internal) { if (moduleName == nullptr) { HILOG_ERROR("moduleName value is null"); @@ -89,7 +89,7 @@ NativeModule* NativeModuleManager::LoadNativeModule(const char* moduleName, bool NativeModule* nativeModule = FindNativeModuleByCache(moduleName); if (nativeModule == nullptr) { HILOG_INFO("not in cache: moduleName: %{public}s", moduleName); - nativeModule = FindNativeModuleByDisk(moduleName, internal); + nativeModule = FindNativeModuleByDisk(moduleName, internal, path); } if (pthread_mutex_unlock(&mutex_) != 0) { @@ -100,15 +100,21 @@ NativeModule* NativeModuleManager::LoadNativeModule(const char* moduleName, bool return nativeModule; } -bool NativeModuleManager::GetNativeModulePath(const char* moduleName, char* nativeModulePath, int32_t pathLength) +bool NativeModuleManager::GetNativeModulePath( + const char* moduleName, const char* path, char* nativeModulePath, int32_t pathLength) const { const char* soPostfix = ".so"; #ifdef _ARM64_ - const char* prefix = "/system/lib64/module"; + const char* sysPrefix = "/system/lib64/module"; #else - const char* prefix = "/system/lib/module"; + const char* sysPrefix = "/system/lib/module"; #endif - + const char* prefix = nullptr; + if (path) { + prefix = path; + } else { + prefix = sysPrefix; + } int32_t lengthOfModuleName = strlen(moduleName); char dupModuleName[PATH_MAX] = { 0 }; if (strcpy_s(dupModuleName, PATH_MAX, moduleName) != 0) { @@ -154,10 +160,10 @@ bool NativeModuleManager::GetNativeModulePath(const char* moduleName, char* nati } using NAPIGetJSCode = void (*)(const char** buf, int* bufLen); -NativeModule* NativeModuleManager::FindNativeModuleByDisk(const char* moduleName, bool internal) +NativeModule* NativeModuleManager::FindNativeModuleByDisk(const char* moduleName, bool internal, const char* path) { char nativeModulePath[PATH_MAX] = { 0 }; - if (!GetNativeModulePath(moduleName, nativeModulePath, sizeof(nativeModulePath))) { + if (!GetNativeModulePath(moduleName, path, nativeModulePath, sizeof(nativeModulePath))) { HILOG_ERROR("get module filed"); return nullptr; } @@ -195,7 +201,7 @@ NativeModule* NativeModuleManager::FindNativeModuleByDisk(const char* moduleName return lastNativeModule_; } -NativeModule* NativeModuleManager::FindNativeModuleByCache(const char* moduleName) +NativeModule* NativeModuleManager::FindNativeModuleByCache(const char* moduleName) const { NativeModule* result = nullptr; for (NativeModule* temp = firstNativeModule_; temp != nullptr; temp = temp->next) { diff --git a/module_manager/native_module_manager.h b/module_manager/native_module_manager.h index 34b8da511..3d24196fe 100644 --- a/module_manager/native_module_manager.h +++ b/module_manager/native_module_manager.h @@ -41,16 +41,17 @@ public: static NativeModuleManager* GetInstance(); static unsigned long Release(); - virtual void Register(NativeModule* nativeModule); - virtual NativeModule* LoadNativeModule(const char* moduleName, bool internal = false); + void Register(NativeModule* nativeModule); + NativeModule* LoadNativeModule(const char* moduleName, const char* path, bool internal = false); private: NativeModuleManager(); virtual ~NativeModuleManager(); - bool GetNativeModulePath(const char* moduleName, char* nativeModulePath, int32_t pathLength); - virtual NativeModule* FindNativeModuleByDisk(const char* moduleName, bool internal); - virtual NativeModule* FindNativeModuleByCache(const char* moduleName); + bool GetNativeModulePath( + const char* moduleName, const char* path, char* nativeModulePath, int32_t pathLength) const; + NativeModule* FindNativeModuleByDisk(const char* moduleName, bool internal, const char* path); + NativeModule* FindNativeModuleByCache(const char* moduleName) const; NativeModule* firstNativeModule_; NativeModule* lastNativeModule_; diff --git a/native_engine/impl/quickjs/quickjs_ext.cpp b/native_engine/impl/quickjs/quickjs_ext.cpp index e3f703481..c01abfb41 100644 --- a/native_engine/impl/quickjs/quickjs_ext.cpp +++ b/native_engine/impl/quickjs/quickjs_ext.cpp @@ -26,7 +26,7 @@ struct JSObjectInfo { void* hint = nullptr; }; -JSClassID g_baseClassId = 0; +JSClassID g_baseClassId = 1; void AddIntrinsicExternal(JSContext* context) { diff --git a/native_engine/impl/quickjs/quickjs_native_engine.cpp b/native_engine/impl/quickjs/quickjs_native_engine.cpp index 753599786..2f243cf96 100644 --- a/native_engine/impl/quickjs/quickjs_native_engine.cpp +++ b/native_engine/impl/quickjs/quickjs_native_engine.cpp @@ -29,9 +29,14 @@ #include "native_value/quickjs_native_typed_array.h" #include "quickjs_native_deferred.h" #include "quickjs_native_reference.h" +#include "securec.h" +#include "utils/assert.h" #include "utils/log.h" +const int JS_WRITE_OBJ = (1 << 2) | (1 << 3); +const int JS_ATOM_MESSAGE = 51; + QuickJSNativeEngine::QuickJSNativeEngine(JSRuntime* runtime, JSContext* context) { runtime_ = runtime; @@ -58,7 +63,7 @@ QuickJSNativeEngine::QuickJSNativeEngine(JSRuntime* runtime, JSContext* context) } NativeModuleManager* moduleManager = that->GetModuleManager(); - NativeModule* module = moduleManager->LoadNativeModule(moduleName, true); + NativeModule* module = moduleManager->LoadNativeModule(moduleName, nullptr, true); if (module != nullptr && module->registerCallback != nullptr) { NativeValue* value = new QuickJSNativeObject(that); @@ -79,16 +84,18 @@ QuickJSNativeEngine::QuickJSNativeEngine(JSRuntime* runtime, JSContext* context) JSValue result = JS_UNDEFINED; QuickJSNativeEngine* that = (QuickJSNativeEngine*)JS_VALUE_GET_PTR(funcData[0]); - const char* moduleName = JS_ToCString(that->GetContext(), argv[0]); - if (moduleName == nullptr || strlen(moduleName) == 0) { HILOG_ERROR("moduleName is nullptr or length is 0"); return result; } + const char* path = nullptr; + if (argc == 2) { + path = JS_ToCString(that->GetContext(), argv[1]); + } NativeModuleManager* moduleManager = that->GetModuleManager(); - NativeModule* module = moduleManager->LoadNativeModule(moduleName); + NativeModule* module = moduleManager->LoadNativeModule(moduleName, nullptr); if (module != nullptr) { if (module->jsCode != nullptr) { @@ -330,6 +337,10 @@ NativeValue* QuickJSNativeEngine::CallFunction(NativeValue* thisVar, scopeManager_->Close(scope); + if (JS_IsError(context_, result) || JS_IsException(result)) { + return nullptr; + } + return JSValueToNativeValue(this, result); } @@ -339,6 +350,9 @@ NativeValue* QuickJSNativeEngine::RunScript(NativeValue* script) const char* cScript = JS_ToCString(context_, *script); result = JS_Eval(context_, cScript, strlen(cScript), "", JS_EVAL_TYPE_GLOBAL); JS_FreeCString(context_, cScript); + if (JS_IsError(context_, result) || JS_IsException(result)) { + return nullptr; + } return JSValueToNativeValue(this, result); } @@ -357,14 +371,14 @@ NativeValue* QuickJSNativeEngine::LoadModule(NativeValue* str, const std::string JSValue moduleVal = JS_Eval(context_, moduleSource, len, fileName.c_str(), flags); if (JS_IsException(moduleVal)) { HILOG_ERROR("Eval source code exception"); - JS_FreeCString(context_, moduleSource); + JS_FreeCString(context_, moduleSource); return nullptr; } JSValue evalRes = JS_EvalFunction(context_, moduleVal); if (JS_IsException(evalRes)) { HILOG_ERROR("Eval module exception"); - JS_FreeCString(context_, moduleSource); + JS_FreeCString(context_, moduleSource); return nullptr; } @@ -564,3 +578,116 @@ NativeValue* QuickJSNativeEngine::JSValueToNativeValue(QuickJSNativeEngine* engi } return result; } + + void* QuickJSNativeEngine::CreateRuntime() + { + JSRuntime* runtime = JS_NewRuntime(); + JSContext* context = JS_NewContext(runtime); + return reinterpret_cast(new QuickJSNativeEngine(runtime, context)); +} + +bool QuickJSNativeEngine::CheckTransferList(JSValue transferList) +{ + if (JS_IsUndefined(transferList)) { + return true; + } + if (!JS_IsArray(context_, transferList)) { + JS_ThrowTypeError(context_, "postMessage second parameter not a list or undefined"); + return false; + } + int64_t len = 0; + js_get_length64(context_, &len, transferList); + for (int64_t i = 0; i < len; i++) { + JSValue tmp = JS_GetPropertyInt64(context_, transferList, i); + if (!JS_IsException(tmp)) { + if (!JS_IsArrayBuffer(context_, tmp)) { + HILOG_ERROR("JS_ISArrayBuffer fail"); + return false; + } + } else { + HILOG_ERROR("JS_GetPropertyInt64 fail"); + return false; + } + } + return true; +} + +bool QuickJSNativeEngine::DetachTransferList(JSValue transferList) +{ + if (JS_IsUndefined(transferList)) { + return true; + } + int64_t len = 0; + js_get_length64(context_, &len, transferList); + for (int64_t i = 0; i < len; i++) { + JSValue tmp = JS_GetPropertyInt64(context_, transferList, i); + if (!JS_IsException(tmp)) { + JS_DetachArrayBuffer(context_, tmp); + } else { + return false; + } + } + return true; + +} + +NativeValue* QuickJSNativeEngine::Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer) +{ + if (!CheckTransferList(*transfer)) { + return nullptr; + } + size_t dataLen; + uint8_t *data = JS_WriteObject(context_, &dataLen, *value, JS_WRITE_OBJ); + DetachTransferList(*transfer); + return reinterpret_cast(new SerializeData(dataLen, data)); +} + +NativeValue* QuickJSNativeEngine::Deserialize(NativeEngine* context, NativeValue* recorder) +{ + std::unique_ptr data(reinterpret_cast(recorder)); + JSValue result = JS_ReadObject(context_, data->GetData(), data->GetSize(), JS_WRITE_OBJ); + return JSValueToNativeValue(this, result); +} + +void QuickJSNativeEngine::DeleteSerializationData(NativeValue* value) const +{ + SerializeData* data = reinterpret_cast(value); + delete data; +} + +ExceptionInfo* QuickJSNativeEngine::GetExceptionForWorker() const +{ + JSValue exception = JS_GetCurrentException(runtime_); + ASSERT(JS_IsObject(exception)); + JSValue msg; + ExceptionInfo* exceptionInfo = new ExceptionInfo(); + msg = JS_GetProperty(context_, exception, JS_ATOM_MESSAGE); + ASSERT(JS_IsString(msg)); + const char* exceptionStr = reinterpret_cast(JS_GetStringFromObject(msg)); + const char* error = "Error: "; + int len = strlen(exceptionStr) + strlen(error) + 1; + if (len <= 0) { + return nullptr; + } + char* exceptionMessage = new char[len] { 0 }; + if (memcpy_s(exceptionMessage, len, error, strlen(error)) != EOK) { + HILOG_INFO("worker:: memcpy_s error"); + delete exceptionInfo; + delete[] exceptionMessage; + return nullptr; + } + if (memcpy_s(exceptionMessage + strlen(error), len, exceptionStr, strlen(exceptionStr)) != EOK) { + HILOG_INFO("worker:: memcpy_s error"); + delete exceptionInfo; + delete[] exceptionMessage; + return nullptr; + } + exceptionInfo->message_ = exceptionMessage; + return exceptionInfo; +} + + NativeValue* QuickJSNativeEngine::ValueToNativeValue(JSValueWrapper& value) + { + JSValue quickValue = value; + return JSValueToNativeValue(this, quickValue); +} \ No newline at end of file diff --git a/native_engine/impl/quickjs/quickjs_native_engine.h b/native_engine/impl/quickjs/quickjs_native_engine.h index 072a4f0b3..20cc2db15 100644 --- a/native_engine/impl/quickjs/quickjs_native_engine.h +++ b/native_engine/impl/quickjs/quickjs_native_engine.h @@ -19,6 +19,32 @@ #include "native_engine/native_engine.h" #include "quickjs_headers.h" +class SerializeData { +public: + SerializeData(size_t size, uint8_t *data) : dataSize_(size), value_(data) {} + ~SerializeData() = default; + + uint8_t* GetData() const + { + return value_.get(); + } + size_t GetSize() const + { + return dataSize_; + } + +private: + struct Deleter { + void operator()(uint8_t* ptr) const + { + free(ptr); + } + }; + + size_t dataSize_; + std::unique_ptr value_; +}; + class QuickJSNativeEngine : public NativeEngine { public: QuickJSNativeEngine(JSRuntime* runtime, JSContext* context); @@ -77,9 +103,18 @@ public: virtual bool Throw(NativeValue* error) override; virtual bool Throw(NativeErrorType type, const char* code, const char* message) override; + virtual void* CreateRuntime() override; + bool CheckTransferList(JSValue transferList); + bool DetachTransferList(JSValue transferList); + virtual NativeValue* Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer) override; + virtual NativeValue* Deserialize(NativeEngine* context, NativeValue* recorder) override; + virtual void DeleteSerializationData(NativeValue* value) const override; + virtual ExceptionInfo* GetExceptionForWorker() const override; + virtual NativeValue* LoadModule(NativeValue* str, const std::string& fileName) override; static NativeValue* JSValueToNativeValue(QuickJSNativeEngine* engine, JSValue value); + virtual NativeValue* ValueToNativeValue(JSValueWrapper& value) override; private: JSRuntime* runtime_; diff --git a/native_engine/impl/quickjs/quickjs_native_reference.cpp b/native_engine/impl/quickjs/quickjs_native_reference.cpp index da02027a2..1e8b94ac8 100644 --- a/native_engine/impl/quickjs/quickjs_native_reference.cpp +++ b/native_engine/impl/quickjs/quickjs_native_reference.cpp @@ -59,7 +59,7 @@ uint32_t QuickJSNativeReference::Unref() NativeValue* QuickJSNativeReference::Get() { - return new QuickJSNativeValue(engine_, JS_DupValue(engine_->GetContext(), value_)); + return QuickJSNativeEngine::JSValueToNativeValue(engine_, JS_DupValue(engine_->GetContext(), value_)); } QuickJSNativeReference::operator NativeValue*() diff --git a/native_engine/native_api.cpp b/native_engine/native_api.cpp index 5c5c5e19c..9cec57482 100644 --- a/native_engine/native_api.cpp +++ b/native_engine/native_api.cpp @@ -1595,3 +1595,92 @@ NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env, int64_t change return napi_clear_last_error(env); } + +NAPI_EXTERN napi_status napi_create_runtime(napi_env env, napi_env* result_env) +{ + CHECK_ENV(env); + CHECK_ARG(env, result_env); + + auto engine = reinterpret_cast(env); + + auto result = engine->CreateRuntime(); + *result_env = reinterpret_cast(result); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_serialize(napi_env env, napi_value object, napi_value transfer_list, napi_value* result) +{ + CHECK_ENV(env); + CHECK_ARG(env, object); + CHECK_ARG(env, transfer_list); + CHECK_ARG(env, result); + + auto engine = reinterpret_cast(env); + auto nativeValue = reinterpret_cast(object); + auto transferList = reinterpret_cast(transfer_list); + + auto resultValue = engine->Serialize(engine, nativeValue, transferList); + *result = reinterpret_cast(resultValue); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_deserialize(napi_env env, napi_value recorder, napi_value* object) +{ + CHECK_ENV(env); + CHECK_ARG(env, recorder); + CHECK_ARG(env, object); + + auto engine = reinterpret_cast(env); + auto recorderValue = reinterpret_cast(recorder); + + auto result = engine->Deserialize(engine, recorderValue); + *object = reinterpret_cast(result); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_delete_serialization_data(napi_env env, napi_value value) +{ + CHECK_ENV(env); + CHECK_ARG(env, value); + + auto engine = reinterpret_cast(env); + auto nativeValue = reinterpret_cast(value); + + engine->DeleteSerializationData(nativeValue); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_get_exception_info_for_worker(napi_env env, napi_value obj) +{ + CHECK_ENV(env); + CHECK_ARG(env, obj); + + auto engine = reinterpret_cast(env); + ExceptionInfo* exceptionInfo = engine->GetExceptionForWorker(); + if (exceptionInfo == nullptr) { + HILOG_INFO("engine get exception info error"); + return napi_invalid_arg; + } + + napi_value lineno = nullptr; + napi_create_int32(env, exceptionInfo->lineno_, &lineno); + napi_set_named_property(env, obj, "lineno", lineno); + + napi_value colno = nullptr; + napi_create_int32(env, exceptionInfo->colno_, &lineno); + napi_set_named_property(env, obj, "colno", colno); + + if (exceptionInfo->message_ != nullptr) { + napi_value messageValue = nullptr; + uint32_t messageLen = strlen(exceptionInfo->message_); + napi_create_strting_utf8(env, exceptionInfo->message_, messageLen, &messageValue); + napi_set_named_property(env, obj, "message", messageValue); + } + + delete exceptionInfo; + return napi_clear_last_error(env); +} \ No newline at end of file diff --git a/native_engine/native_async_work.cpp b/native_engine/native_async_work.cpp index 404cd652c..71ddaa1a7 100644 --- a/native_engine/native_async_work.cpp +++ b/native_engine/native_async_work.cpp @@ -60,6 +60,53 @@ bool NativeAsyncWork::Cancel() return true; } +void NativeAsyncWork::AsyncWorkRecvCallback(const uv_async_t* req) +{ + NativeAsyncWork* that = NativeAsyncWork::DereferenceOf(&NativeAsyncWork::workAsyncHandler_, req); + if (that == nullptr) { + return; + } + NativeAsyncWorkDataPointer res; + while (that->PopData(&res)) { + if (that->execute_ != nullptr) { + that->execute_(that->engine_, res.data_); + } + if (that->complete_ != nullptr) { + that->complete_(that->engine_, -1, res.data_); + } + } +} + +void NativeAsyncWork::Send(void* data) +{ + std::lock_guard lock(workAsyncMutex_); + NativeAsyncWorkDataPointer dataPointer(data); + asyncWorkRecvData_.push(dataPointer); + uv_async_send(&workAsyncHandler_); +} + +bool NativeAsyncWork::PopData(NativeAsyncWorkDataPointer* data) +{ + std::lock_guard lock(workAsyncMutex_); + if (asyncWorkRecvData_.empty()) { + return false; + } + *data = asyncWorkRecvData_.front(); + asyncWorkRecvData_.pop(); + return true; +} + +bool NativeAsyncWork::Init() +{ + uv_loop_t* loop = engine_->GetUVLoop(); + if (loop == nullptr) { + HILOG_ERROR("Get loop failed"); + return false; + } + uv_async_init(loop, &workAsyncHandler_, reinterpret_cast(AsyncWorkRecvCallback)); + return true; +} + void NativeAsyncWork::AsyncWorkCallback(uv_work_t* req) { if (req == nullptr) { diff --git a/native_engine/native_async_work.h b/native_engine/native_async_work.h index 4e3f617e6..d9f47ce4f 100644 --- a/native_engine/native_async_work.h +++ b/native_engine/native_async_work.h @@ -18,8 +18,23 @@ #include "native_value.h" +#include +#include #include +struct NativeAsyncWorkDataPointer { + NativeAsyncWorkDataPointer() + { + data_ = nullptr; + } + + explicit NativeAsyncWorkDataPointer(void* data) + { + data_ = data; + } + void* data_ { nullptr }; +}; + class NativeAsyncWork { public: NativeAsyncWork(NativeEngine* engine, @@ -30,19 +45,36 @@ public: virtual ~NativeAsyncWork(); virtual bool Queue(); virtual bool Cancel(); + virtual bool Init(); + virtual void Send(void* data); + virtual bool PopData(NativeAsyncWorkDataPointer* data); + + template + static Outer* DereferenceOf(const Inner Outer::*field, const Inner* pointer) + { + if (field != nullptr && pointer != nullptr) { + auto fieldOffset = reinterpret_cast(&(static_cast(0)->*field)); + auto outPointer = reinterpret_cast(reinterpret_cast(pointer) - fieldOffset); + return outPointer; + } + return nullptr; + } private: static void AsyncWorkCallback(uv_work_t* req); static void AsyncAfterWorkCallback(uv_work_t* req, int status); + static void AsyncWorkRecvCallback(const uv_async_t* req); uv_work_t work_; - + uv_async_t workAsyncHandler_; NativeEngine* engine_; int status_; NativeAsyncExecuteCallback execute_; NativeAsyncCompleteCallback complete_; void* data_; + std::mutex workAsyncMutex_; + std::queue asyncWorkRecvData_; }; #endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ASYNC_WORK_H */ diff --git a/native_engine/native_engine.cpp b/native_engine/native_engine.cpp index 21b94b27a..922f9dd2c 100644 --- a/native_engine/native_engine.cpp +++ b/native_engine/native_engine.cpp @@ -14,6 +14,7 @@ */ #include "native_engine.h" +#include "utils/log.h" #include @@ -92,6 +93,13 @@ NativeAsyncWork* NativeEngine::CreateAsyncWork(NativeValue* asyncResource, return new NativeAsyncWork(this, execute, complete, data); } +NativeAsyncWork* NativeEngine::CreateAsyncWork(NativeAsyncExecuteCallback execute, + NativeAsyncCompleteCallback complete, + void* data) +{ + return new NativeAsyncWork(this, execute, complete, data); +} + NativeErrorExtendedInfo* NativeEngine::GetLastError() { return &lastError_; @@ -124,3 +132,38 @@ NativeValue* NativeEngine::GetAndClearLastException() lastException_ = nullptr; return temp; } + +void NativeEngine::EncodeToUtf8(NativeValue* nativeValue, + char* buffer, + int32_t* written, + size_t bufferSize, + int32_t* nchars) +{ + if (nativeValue == nullptr || nchars == nullptr || written == nullptr) { + HILOG_ERROR("NativeEngine EncodeToUtf8 args is nullptr"); + return; + } + + auto nativeString = reinterpret_cast(nativeValue->GetInterface(NativeString::INTERFACE_ID)); + + if (nativeString == nullptr) { + HILOG_ERROR("nativeValue GetInterface is nullptr"); + return; + } + *written = nativeString->EncodeWriteUtf8(buffer, bufferSize, nchars); +} + +void NativeEngine::SetPostTask(PostTask postTask) +{ + HILOG_INFO("SetPostTask in"); + postTask_ = postTask; +} + +void NativeEngine::TriggerPostTask() +{ + if (postTask_ == nullptr) { + HILOG_ERROR("postTask_ is nullptr"); + return; + } + postTask_(); +} diff --git a/native_engine/native_engine.h b/native_engine/native_engine.h index 902f31ccf..e9a2d3f93 100644 --- a/native_engine/native_engine.h +++ b/native_engine/native_engine.h @@ -35,6 +35,25 @@ struct NativeErrorExtendedInfo { int errorCode = 0; }; +struct ExceptionInfo { + const char* message_ = nullptr; + int32_t lineno_ = 0; + int32_t colno_ = 0; + + ~ExceptionInfo() + { + if (message_ != nullptr) { + delete[] message_; + } + } +}; + +enum LoopMode { + LOOP_DEFAULT, LOOP_ONCE, LOOP_NOWAIT +} + +using PostTask = std::function; + class NativeEngine { public: NativeEngine(); @@ -44,7 +63,9 @@ public: virtual NativeModuleManager* GetModuleManager(); virtual uv_loop_t* GetUVLoop() const; - virtual void Loop(); + virtual void Loop(LoopMode mode); + virtual void SetPostTask(PostTask postTask); + virtual void TriggerPostTask(); virtual NativeValue* GetGlobal() = 0; @@ -93,11 +114,22 @@ public: NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete, void* data); + + virtual NativeAsyncWork* CreateAsyncWork(NativeAsyncExecuteCallback execute, + NativeAsyncCompleteCallback complete, + void* data); + virtual NativeReference* CreateReference(NativeValue* value, uint32_t initialRefcount) = 0; virtual bool Throw(NativeValue* error) = 0; virtual bool Throw(NativeErrorType type, const char* code, const char* message) = 0; + virtual void* CreateRuntime() = 0; + virtual NativeValue* Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer) = 0; + virtual NativeValue* Deserialize(NativeEngine* context, NativeValue* recorder) = 0; + virtual ExceptionInfo* GetExceptionForWorker() const = 0; + virtual void DeleteSerializationData(NativeValue* value) const = 0; + virtual NativeValue* LoadModule(NativeValue* str, const std::string& fileName) = 0; NativeErrorExtendedInfo* GetLastError(); @@ -105,15 +137,31 @@ public: void ClearLastError(); bool IsExceptionPending() const; NativeValue* GetAndClearLastException(); + void EncodeToUtf8(NativeValue* nativeValue, char* buffer, int32_t* written, size_t bufferSize, int32_t* nchars); + + void MarkSubThread() + { + isMainThread_ = false; + } + + bool IsMainThread() const + { + return isMainThread_; + } + protected: - NativeModuleManager* moduleManager_; - NativeScopeManager* scopeManager_; + NativeModuleManager* moduleManager_ { nullptr }; + NativeScopeManager* scopeManager_ { nullptr }; NativeErrorExtendedInfo lastError_; - NativeValue* lastException_; + NativeValue* lastException_ { nullptr }; uv_loop_t* loop_; + +private: + bool isMainThread_ { nullptr }; + PostTask postTask_ { nullptr }; }; #endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H */ -- Gitee