From 6ed6ea4d388067058a012bce79dabe13ea5c13f0 Mon Sep 17 00:00:00 2001 From: weibaoxiang Date: Tue, 9 Sep 2025 17:21:57 +0800 Subject: [PATCH 1/2] test Change-Id: Ie1e71cfbae174ceaabcc82336b7621a994f5e666 --- .../runtime/interop_js/call/arg_convertors.h | 1 + .../ets_proxy/ets_class_wrapper.cpp | 26 +++- .../interop_js/ets_proxy/ets_class_wrapper.h | 2 + .../ets_proxy/ets_field_wrapper.cpp | 6 +- .../ets_proxy/shared_reference_storage.cpp | 35 ++++- .../ets_proxy/shared_reference_storage.h | 4 + .../ets/runtime/interop_js/interop_common.h | 130 +++++++++++++++--- .../runtime/interop_js/interop_context.cpp | 2 +- .../ets/runtime/interop_js/js_convert.h | 9 +- .../ets/runtime/interop_js/js_convert_base.h | 31 ++++- .../runtime/interop_js/js_convert_stdlib.h | 2 + .../interop_js/js_refconvert_builtin.cpp | 39 ++++-- .../interop_js/js_refconvert_record.cpp | 2 +- .../ets/runtime/interop_js/js_value.cpp | 20 ++- .../plugins/ets/runtime/interop_js/js_value.h | 6 +- .../interop_js/xref_object_operator.cpp | 9 +- .../ets/runtime/intrinsics/escompat_Array.cpp | 4 +- .../tests/concurrency/CMakeLists.txt | 2 +- 18 files changed, 265 insertions(+), 65 deletions(-) diff --git a/static_core/plugins/ets/runtime/interop_js/call/arg_convertors.h b/static_core/plugins/ets/runtime/interop_js/call/arg_convertors.h index 6ebacdc1f4..2a6ddd50d8 100644 --- a/static_core/plugins/ets/runtime/interop_js/call/arg_convertors.h +++ b/static_core/plugins/ets/runtime/interop_js/call/arg_convertors.h @@ -16,6 +16,7 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_CALL_ARG_CONVERTORS_H #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_CALL_ARG_CONVERTORS_H +#include "include/thread_scopes.h" #include "plugins/ets/runtime/interop_js/call/proto_reader.h" #include "plugins/ets/runtime/interop_js/js_convert.h" #include "plugins/ets/runtime/types/ets_escompat_array.h" diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp index ef787718cb..454150f4d6 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp @@ -20,6 +20,7 @@ #include #include +#include "include/thread_scopes.h" #include "plugins/ets/runtime/ets_coroutine.h" #include "include/mem/panda_containers.h" #include "interop_js/interop_common.h" @@ -118,7 +119,7 @@ EtsObject *EtsClassWrapper::Unwrap(InteropCtx *ctx, napi_value jsValue) ASSERT(!IsUndefined(env, jsValue)); // Check if object has SharedReference - SharedReference *sharedRef = ctx->GetSharedRefStorage()->GetReference(env, jsValue); + SharedReference *sharedRef = ctx->GetSharedRefStorage()->GetReference(env, jsValue); if (LIKELY(sharedRef != nullptr)) { EtsObject *etsObject = sharedRef->GetEtsObject(); if (UNLIKELY(!etsClass_->IsAssignableFrom(etsObject->GetClass()))) { @@ -150,7 +151,7 @@ EtsObject *EtsClassWrapper::UnwrapEtsProxy(InteropCtx *ctx, napi_value jsValue) ASSERT(!IsNullOrUndefined(env, jsValue)); // Check if object has SharedReference - SharedReference *sharedRef = ctx->GetSharedRefStorage()->GetReference(env, jsValue); + SharedReference *sharedRef = ctx->GetSharedRefStorage()->GetReference(env, jsValue); if (LIKELY(sharedRef != nullptr)) { EtsObject *etsObject = sharedRef->GetEtsObject(); if (UNLIKELY(!etsClass_->IsAssignableFrom(etsObject->GetClass()))) { @@ -167,7 +168,7 @@ EtsObject *EtsClassWrapper::UnwrapEtsProxy(InteropCtx *ctx, napi_value jsValue) return nullptr; } -EtsObject *EtsClassWrapper::CreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue) +EtsObject *EtsClassWrapper::DoCreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue) { ASSERT(jsproxyWrapper_ != nullptr); auto *storage = ctx->GetSharedRefStorage(); @@ -187,6 +188,16 @@ EtsObject *EtsClassWrapper::CreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsV return sharedRef->GetEtsObject(); // fetch again after gc } +template +EtsObject *EtsClassWrapper::CreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue) +{ + if constexpr (IS_IN_MANAGED) { + ScopedManagedCodeThread managedScope(EtsCoroutine::GetCurrent()); + return DoCreateJSBuiltinProxy(ctx, jsValue); + } + return DoCreateJSBuiltinProxy(ctx, jsValue); +} + /*static*/ std::unique_ptr EtsClassWrapper::CreateJSRefConvertEtsProxy(InteropCtx *ctx, Class *klass) { @@ -263,7 +274,7 @@ public: { auto *coro = EtsCoroutine::GetCurrent(); napi_env env = ctx->GetJSEnv(); - SharedReference *sharedRef = ctx->GetSharedRefStorage()->GetReference(env, jsValue); + SharedReference *sharedRef = ctx->GetSharedRefStorage()->GetReference(env, jsValue); if (LIKELY(sharedRef != nullptr)) { EtsObject *etsObject = sharedRef->GetEtsObject(); return etsObject; @@ -744,7 +755,7 @@ static void SetNullPrototype(napi_env env, napi_value jsCtor) napi_value prot; NAPI_CHECK_FATAL(napi_get_named_property(env, jsCtor, "prototype", &prot)); - napi_value trueValue = GetBooleanValue(env, true); + napi_value trueValue = GetBoolean(env, true); NAPI_CHECK_FATAL(napi_set_named_property(env, jsCtor, IS_STATIC_PROXY.data(), trueValue)); NAPI_CHECK_FATAL(napi_set_named_property(env, prot, IS_STATIC_PROXY.data(), trueValue)); @@ -763,7 +774,7 @@ static void SimulateJSInheritance(napi_env env, napi_value jsCtor, napi_value js DoSetPrototype(env, jsCtor, jsBaseCtor); DoSetPrototype(env, cprototype, baseCprototype); - napi_value trueValue = GetBooleanValue(env, true); + napi_value trueValue = GetBoolean(env, true); NAPI_CHECK_FATAL(napi_set_named_property(env, jsCtor, IS_STATIC_PROXY.data(), trueValue)); NAPI_CHECK_FATAL(napi_set_named_property(env, cprototype, IS_STATIC_PROXY.data(), trueValue)); } @@ -1114,4 +1125,7 @@ bool EtsClassWrapper::CreateAndWrap(napi_env env, napi_value jsNewtarget, napi_v return callRes != nullptr; } +// Explicit instantiation +template EtsObject *EtsClassWrapper::CreateJSBuiltinProxy(InteropCtx *, napi_value); +template EtsObject *EtsClassWrapper::CreateJSBuiltinProxy(InteropCtx *, napi_value); } // namespace ark::ets::interop::js::ets_proxy diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h index 4dce043411..b8895ed0bf 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h @@ -109,6 +109,7 @@ public: EtsObject *Unwrap(InteropCtx *ctx, napi_value jsValue); EtsObject *UnwrapEtsProxy(InteropCtx *ctx, napi_value jsValue); + template EtsObject *CreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue); ~EtsClassWrapper() = default; @@ -137,6 +138,7 @@ private: std::pair CalculateFieldsAndMethods(const PropsMap &props); std::vector BuildJSProperties(napi_env &env, Span fields, Span methods); + EtsObject *DoCreateJSBuiltinProxy(InteropCtx *ctx, napi_value jsValue); static napi_value GetGlobalSymbolIterator(napi_env &env); diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_field_wrapper.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_field_wrapper.cpp index 3a92ea0a1c..0109217c7a 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_field_wrapper.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_field_wrapper.cpp @@ -42,7 +42,7 @@ static EtsObject *EtsAccessorsHandleThis(EtsFieldWrapper *fieldWrapper, EtsCorou return etsClass->AsObject(); } - if (UNLIKELY(IsNullOrUndefined(env, jsThis))) { + if (UNLIKELY(IsNullOrUndefined(env, jsThis))) { ctx->ThrowJSTypeError(env, "ets this in set accessor cannot be null or undefined"); return nullptr; } @@ -146,9 +146,9 @@ struct EtsFieldAccessorREFERENCE { napi_value jsValue) { EtsObject *etsValue; - if (IsUndefined(env, jsValue)) { + if (IsUndefined(env, jsValue)) { etsValue = nullptr; - } else if (IsNull(env, jsValue)) { + } else if (IsNull(env, jsValue)) { etsValue = ctx->GetNullValue(); } else { JSRefConvert *refconv = etsFieldWrapper->GetRefConvert(ctx); diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp index 7553211c82..965b6266f5 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp @@ -123,9 +123,8 @@ SharedReference *ExtractMaybeReference(napi_env env, napi_value jsObject) return AtomicLoad(static_cast(data), std::memory_order_acquire); } -SharedReference *SharedReferenceStorage::GetReference(napi_env env, napi_value jsObject) const +SharedReference *SharedReferenceStorage::DoGetReference(napi_env env, napi_value jsObject) const { - ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); void *data = ExtractMaybeReference(env, jsObject); if (UNLIKELY(data == nullptr)) { return nullptr; @@ -133,6 +132,16 @@ SharedReference *SharedReferenceStorage::GetReference(napi_env env, napi_value j return GetReference(data); } +template +SharedReference *SharedReferenceStorage::GetReference(napi_env env, napi_value jsObject) const +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetReference(env, jsObject); + } + return DoGetReference(env, jsObject); +} + SharedReference *SharedReferenceStorage::GetReference(void *data) const { os::memory::ReadLockHolder lock(storageLock_); @@ -330,6 +339,7 @@ SharedReference *SharedReferenceStorage::CreateETSObjectRef(InteropCtx *ctx, Ets return CreateRefCommon<&SharedReference::InitETSObject>(ctx, etsObject, jsObject, callback); } +template SharedReference *SharedReferenceStorage::CreateJSObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject) { auto *coro = EtsCoroutine::GetCurrent(); @@ -337,11 +347,20 @@ SharedReference *SharedReferenceStorage::CreateJSObjectRef(InteropCtx *ctx, EtsO EtsHandle hobject(coro, etsObject); TriggerXGCIfNeeded(ctx); napi_ref jsRef; + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(coro); #if defined(PANDA_JS_ETS_HYBRID_MODE) - NAPI_CHECK_FATAL(napi_create_xref(ctx->GetJSEnv(), jsObject, 1, &jsRef)); + NAPI_CHECK_FATAL(napi_create_xref(ctx->GetJSEnv(), jsObject, 1, &jsRef)); #else - NAPI_CHECK_FATAL(napi_create_reference(ctx->GetJSEnv(), jsObject, 1, &jsRef)); + NAPI_CHECK_FATAL(napi_create_reference(ctx->GetJSEnv(), jsObject, 1, &jsRef)); #endif + } else { +#if defined(PANDA_JS_ETS_HYBRID_MODE) + NAPI_CHECK_FATAL(napi_create_xref(ctx->GetJSEnv(), jsObject, 1, &jsRef)); +#else + NAPI_CHECK_FATAL(napi_create_reference(ctx->GetJSEnv(), jsObject, 1, &jsRef)); +#endif + } os::memory::WriteLockHolder lock(storageLock_); auto *sharedRef = CreateReference<&SharedReference::InitJSObject>(ctx, hobject, jsRef); return sharedRef; @@ -562,4 +581,12 @@ bool SharedReferenceStorage::CheckAlive(void *data) return IsValidItem(sharedRef) && SharedReferenceSanity::CheckAlive(sharedRef); } +// Explicit instantiation +template SharedReference *SharedReferenceStorage::GetReference(napi_env, napi_value) const; +template SharedReference *SharedReferenceStorage::GetReference(napi_env, napi_value) const; + +// Explicit instantiation +template SharedReference *SharedReferenceStorage::CreateJSObjectRef(InteropCtx *, EtsObject *, napi_value); +template SharedReference *SharedReferenceStorage::CreateJSObjectRef(InteropCtx *, EtsObject *, napi_value); + } // namespace ark::ets::interop::js::ets_proxy diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.h b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.h index ff63377b97..1f01fe6d65 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.h +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.h @@ -58,12 +58,14 @@ public: PANDA_PUBLIC_API SharedReference *CreateETSObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject, const PreInitJSObjectCallback &preInitCallback = nullptr); + template SharedReference *CreateJSObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject); SharedReference *CreateJSObjectRefwithWrap(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject); SharedReference *CreateHybridObjectRef(InteropCtx *ctx, EtsObject *etsObject, napi_value jsObject); + template PANDA_PUBLIC_API SharedReference *GetReference(napi_env env, napi_value jsObject) const; PANDA_PUBLIC_API SharedReference *GetReference(EtsObject *etsObject) const; @@ -162,6 +164,8 @@ private: bool HasReferenceWithCtx(SharedReference *ref, InteropCtx *ctx) const; + SharedReference *DoGetReference(napi_env env, napi_value jsObject) const; + PANDA_PUBLIC_API bool CheckAlive(void *data); friend class SharedReference; friend class SharedReference::Iterator; diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.h b/static_core/plugins/ets/runtime/interop_js/interop_common.h index 6f601e32ef..c8362da95d 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_common.h +++ b/static_core/plugins/ets/runtime/interop_js/interop_common.h @@ -16,6 +16,7 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_COMMON_H_ #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_COMMON_H_ +#include "ets_coroutine.h" #include "runtime/include/thread_scopes.h" #include "runtime/mem/refstorage/global_object_storage.h" #include "plugins/ets/runtime/interop_js/logger.h" @@ -137,18 +138,32 @@ void InteropTrace(const char *func, const char *file, int line); // NOLINTEND(cppcoreguidelines-macro-usage) +template class NapiScope { public: explicit NapiScope(napi_env env) : env_(env) { - [[maybe_unused]] auto status = napi_open_handle_scope(env_, &scope_); - ASSERT(status == napi_ok); + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + [[maybe_unused]] auto status = napi_open_handle_scope(env_, &scope_); + ASSERT(status == napi_ok); + } else { + [[maybe_unused]] auto status = napi_open_handle_scope(env_, &scope_); + ASSERT(status == napi_ok); + } } ~NapiScope() { - [[maybe_unused]] auto status = napi_close_handle_scope(env_, scope_); - ASSERT(status == napi_ok); + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + [[maybe_unused]] auto status = napi_close_handle_scope(env_, scope_); + ASSERT(status == napi_ok); + } else { + [[maybe_unused]] auto status = napi_close_handle_scope(env_, scope_); + ASSERT(status == napi_ok); + } + } NO_COPY_SEMANTIC(NapiScope); @@ -187,72 +202,128 @@ private: napi_escapable_handle_scope scope_ {}; }; -inline napi_valuetype GetValueType(napi_env env, napi_value val) +inline napi_valuetype DoGetValueType(napi_env env, napi_value val) { napi_valuetype vtype; NAPI_CHECK_FATAL(napi_typeof(env, val, &vtype)); return vtype; } -inline napi_value GetReferenceValue(napi_env env, napi_ref ref) +template +inline napi_valuetype GetValueType(napi_env env, napi_value val) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetValueType(env, val); + } + return DoGetValueType(env, val); +} + +inline napi_value DoGetReferenceValue(napi_env env, napi_ref ref) { napi_value val; NAPI_CHECK_FATAL(napi_get_reference_value(env, ref, &val)); return val; } -inline napi_value GetUndefined(napi_env env) +template +inline napi_value GetReferenceValue(napi_env env, napi_ref ref) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetReferenceValue(env, ref); + } + return DoGetReferenceValue(env, ref); +} + +inline napi_value DoGetUndefined(napi_env env) { napi_value jsValueUndefined {}; NAPI_CHECK_FATAL(napi_get_undefined(env, &jsValueUndefined)); return jsValueUndefined; } -inline napi_value GetBoolean(napi_env env, bool value) +template +inline napi_value GetUndefined(napi_env env) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetUndefined(env); + } + return DoGetUndefined(env); +} + +inline napi_value DoGetBoolean(napi_env env, bool value) { napi_value result; NAPI_CHECK_FATAL(napi_get_boolean(env, value, &result)); return result; } -inline napi_value GetNull(napi_env env) +template +inline napi_value GetBoolean(napi_env env, bool value) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetBoolean(env, value); + } + return DoGetBoolean(env, value); +} + +inline napi_value DoGetNull(napi_env env) { napi_value jsValueNull {}; NAPI_CHECK_FATAL(napi_get_null(env, &jsValueNull)); return jsValueNull; } -inline napi_value GetGlobal(napi_env env) +template +inline napi_value GetNull(napi_env env) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetNull(env); + } + return DoGetNull(env); +} + +inline napi_value DoGetGlobal(napi_env env) { napi_value jsValueGlobal {}; NAPI_CHECK_FATAL(napi_get_global(env, &jsValueGlobal)); return jsValueGlobal; } -inline napi_value GetBooleanValue(napi_env env, bool val) +template +inline napi_value GetGlobal(napi_env env) { - napi_value jsValueBoolean {}; - NAPI_CHECK_FATAL(napi_get_boolean(env, val, &jsValueBoolean)); - return jsValueBoolean; + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetGlobal(env); + } + return DoGetGlobal(env); } +template inline bool IsNull(napi_env env, napi_value val) { - return GetValueType(env, val) == napi_null; + return GetValueType(env, val) == napi_null; } +template inline bool IsUndefined(napi_env env, napi_value val) { - return GetValueType(env, val) == napi_undefined; + return GetValueType(env, val) == napi_undefined; } +template inline bool IsNullOrUndefined(napi_env env, napi_value val) { - napi_valuetype vtype = GetValueType(env, val); + napi_valuetype vtype = GetValueType(env, val); return vtype == napi_undefined || vtype == napi_null; } -inline std::string GetString(napi_env env, napi_value jsVal) +inline std::string DoGetString(napi_env env, napi_value jsVal) { size_t length; NAPI_CHECK_FATAL(napi_get_value_string_utf8(env, jsVal, nullptr, 0, &length)); @@ -263,13 +334,34 @@ inline std::string GetString(napi_env env, napi_value jsVal) return value; } -inline bool NapiIsExceptionPending(napi_env env) +template +inline std::string GetString(napi_env env, napi_value jsVal) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetString(env, jsVal); + } + return DoGetString(env, jsVal); +} + +inline bool DoNapiIsExceptionPending(napi_env env) { bool pending; NAPI_CHECK_FATAL(napi_is_exception_pending(env, &pending)); return pending; } +template +inline bool NapiIsExceptionPending(napi_env env) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoNapiIsExceptionPending(env); + } + return DoNapiIsExceptionPending(env); +} + + inline bool NapiThrownGeneric(napi_status rc) { INTEROP_FATAL_IF(rc != napi_ok && rc != napi_generic_failure); diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp index 80e5319747..d7f8506df3 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp +++ b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp @@ -274,7 +274,7 @@ void CommonJSObjectCache::InitializeRecordProto() napi_value protoObj; NAPI_CHECK_FATAL(napi_create_object(env, &protoObj)); - napi_value trueValue = GetBooleanValue(env, true); + napi_value trueValue = GetBoolean(env, true); NAPI_CHECK_FATAL(napi_set_named_property(env, protoObj, IS_STATIC_PROXY.data(), trueValue)); NAPI_CHECK_FATAL(napi_create_reference(env, protoObj, 1, &recordProtoRef_)); } diff --git a/static_core/plugins/ets/runtime/interop_js/js_convert.h b/static_core/plugins/ets/runtime/interop_js/js_convert.h index 6cdd7d78a6..9ffb620199 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_convert.h +++ b/static_core/plugins/ets/runtime/interop_js/js_convert.h @@ -16,6 +16,7 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_H #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_H +#include "include/thread_scopes.h" #include "js_convert_base.h" #include "js_convert_stdlib.h" #include "napi_impl/ark_napi_helper.h" @@ -445,8 +446,12 @@ ALWAYS_INLINE inline std::optional JSValueGetByName(Interop { auto env = ctx->GetJSEnv(); auto coro = EtsCoroutine::GetCurrent(); - napi_value jsVal = jsvalue->GetNapiValue(env); - auto result = common::DynamicObjectAccessorUtil::GetProperty(ArkNapiHelper::ToBaseObject(jsVal), name); + TaggedType *result = nullptr; + { + ScopedNativeCodeThread nativeScope(coro); + napi_value jsVal = jsvalue->GetNapiValue(env); + result = common::DynamicObjectAccessorUtil::GetProperty(ArkNapiHelper::ToBaseObject(jsVal), name); + } if (NapiIsExceptionPending(env)) { ctx->ForwardJSException(coro); return {}; diff --git a/static_core/plugins/ets/runtime/interop_js/js_convert_base.h b/static_core/plugins/ets/runtime/interop_js/js_convert_base.h index 434f4eeb01..be713c8012 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_convert_base.h +++ b/static_core/plugins/ets/runtime/interop_js/js_convert_base.h @@ -56,7 +56,7 @@ inline void JSConvertTypeCheckFailed(const std::string &s) JSConvertTypeCheckFailed(s.c_str()); } -static bool IsConstructor(napi_env &env, napi_value &jsValue, const char *constructorName) +static bool DoIsConstructor(napi_env &env, napi_value &jsValue, const char *constructorName) { napi_value constructor; bool isInstanceof; @@ -65,7 +65,18 @@ static bool IsConstructor(napi_env &env, napi_value &jsValue, const char *constr return isInstanceof; } -static bool GetValueByValueOf(napi_env env, napi_value &jsValue, const char *constructorName, napi_value *result) +template +static bool IsConstructor(napi_env &env, napi_value &jsValue, const char *constructorName) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoIsConstructor(env, jsValue, constructorName); + } + return DoIsConstructor(env, jsValue, constructorName); +} + + +static bool DoGetValueByValueOf(napi_env env, napi_value &jsValue, const char *constructorName, napi_value *result) { if (!IsConstructor(env, jsValue, constructorName)) { return false; @@ -76,6 +87,16 @@ static bool GetValueByValueOf(napi_env env, napi_value &jsValue, const char *con return true; } +template +static bool GetValueByValueOf(napi_env env, napi_value &jsValue, const char *constructorName, napi_value *result) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetValueByValueOf(env, jsValue, constructorName, result); + } + return DoGetValueByValueOf(env, jsValue, constructorName, result); +} + // Base mixin class of JSConvert interface // Represents primitive types and some built-in classes, has no state template @@ -106,7 +127,7 @@ struct JSConvertBase { static std::optional Unwrap(InteropCtx *ctx, napi_env env, napi_value jsVal) { if constexpr (IS_REFTYPE) { - ASSERT(!IsUndefined(env, jsVal)); + ASSERT(!IsUndefined(env, jsVal)); } auto res = Impl::UnwrapImpl(ctx, env, jsVal); ASSERT(res.has_value() || InteropCtx::SanityJSExceptionPending() || InteropCtx::SanityETSExceptionPending()); @@ -117,7 +138,7 @@ struct JSConvertBase { { if constexpr (IS_REFTYPE) { if (UNLIKELY(etsVal == nullptr)) { - return GetUndefined(env); + return GetUndefined(env); } } auto res = Impl::WrapImpl(env, etsVal); @@ -129,7 +150,7 @@ struct JSConvertBase { { if constexpr (IS_REFTYPE) { // NOTE(kprokopenko) can't assign null to EtsString *, hence fallback into UnwrapImpl - if (UNLIKELY(IsUndefined(env, jsVal))) { + if (UNLIKELY(IsUndefined(env, jsVal))) { return nullptr; } } diff --git a/static_core/plugins/ets/runtime/interop_js/js_convert_stdlib.h b/static_core/plugins/ets/runtime/interop_js/js_convert_stdlib.h index e972153271..a01c7afe51 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_convert_stdlib.h +++ b/static_core/plugins/ets/runtime/interop_js/js_convert_stdlib.h @@ -16,6 +16,8 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_STDLIB_H #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_STDLIB_H +#include "ets_coroutine.h" +#include "include/thread_scopes.h" #include "js_convert_base.h" namespace ark::ets::interop::js { diff --git a/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp b/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp index 6913f17c79..2d30d28452 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp +++ b/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp @@ -126,6 +126,7 @@ private: template EtsObject *BuiltinConvert(InteropCtx *inCtx, napi_env env, napi_value jsValue) { + ScopedManagedCodeThread managedScope(EtsCoroutine::GetCurrent()); auto res = ConvTag::UnwrapImpl(inCtx, env, jsValue); if (UNLIKELY(!res.has_value())) { return nullptr; @@ -281,6 +282,7 @@ private: wDate_ = RegisterClassWithLeafMatcher(descriptors::DATE, "Date", &W_DATE_OVERLOADS); } + template EtsObject *MArray(InteropCtx *ctxx, napi_value jsValue, bool verified = true) { napi_env env = ctxx->GetJSEnv(); @@ -291,9 +293,10 @@ private: return NotAssignable("Array"); } } - return wArray_->CreateJSBuiltinProxy(ctxx, jsValue); + return wArray_->CreateJSBuiltinProxy(ctxx, jsValue); } + template EtsObject *MMap(InteropCtx *ctxx, napi_value jsValue, bool verified = true) { napi_env env = ctxx->GetJSEnv(); @@ -304,9 +307,10 @@ private: return NotAssignable("Map"); } } - return wMap_->CreateJSBuiltinProxy(ctxx, jsValue); + return wMap_->CreateJSBuiltinProxy(ctxx, jsValue); } + template EtsObject *MSet(InteropCtx *ctxx, napi_value jsValue, bool verified = true) { napi_env env = ctxx->GetJSEnv(); @@ -317,9 +321,10 @@ private: return NotAssignable("Set"); } } - return wSet_->CreateJSBuiltinProxy(ctxx, jsValue); + return wSet_->CreateJSBuiltinProxy(ctxx, jsValue); } + template EtsObject *MDate(InteropCtx *ctxx, napi_value jsValue, bool verified = true) { napi_env env = ctxx->GetJSEnv(); @@ -331,7 +336,7 @@ private: } } ASSERT(wDate_ != nullptr); - return wDate_->CreateJSBuiltinProxy(ctxx, jsValue); + return wDate_->CreateJSBuiltinProxy(ctxx, jsValue); } void RegisterObject() @@ -339,6 +344,7 @@ private: wObject_ = RegisterClass(descriptors::OBJECT, "Object"); } + template EtsObject *MError(InteropCtx *ctxx, napi_value jsValue, bool verified = true) { napi_env env = ctxx->GetJSEnv(); @@ -351,22 +357,22 @@ private: } if (CheckInstanceof(env, jsValue, ctorRangeError_)) { - return wRangeError_->CreateJSBuiltinProxy(ctxx, jsValue); + return wRangeError_->CreateJSBuiltinProxy(ctxx, jsValue); } if (CheckInstanceof(env, jsValue, ctorReferenceError_)) { - return wReferenceError_->CreateJSBuiltinProxy(ctxx, jsValue); + return wReferenceError_->CreateJSBuiltinProxy(ctxx, jsValue); } if (CheckInstanceof(env, jsValue, ctorSyntaxError_)) { - return wSyntaxError_->CreateJSBuiltinProxy(ctxx, jsValue); + return wSyntaxError_->CreateJSBuiltinProxy(ctxx, jsValue); } if (CheckInstanceof(env, jsValue, ctorURIError_)) { - return wURIError_->CreateJSBuiltinProxy(ctxx, jsValue); + return wURIError_->CreateJSBuiltinProxy(ctxx, jsValue); } if (CheckInstanceof(env, jsValue, ctorTypeError_)) { - return wTypeError_->CreateJSBuiltinProxy(ctxx, jsValue); + return wTypeError_->CreateJSBuiltinProxy(ctxx, jsValue); } - return wError_->CreateJSBuiltinProxy(ctxx, jsValue); + return wError_->CreateJSBuiltinProxy(ctxx, jsValue); } EtsObject *MObjectObject(InteropCtx *ctxx, napi_value jsValue) @@ -375,15 +381,15 @@ private: bool isInstanceof; NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof)); if (isInstanceof) { - return MArray(ctxx, jsValue); + return MArray(ctxx, jsValue); } NAPI_CHECK_FATAL(napi_is_map(env, jsValue, &isInstanceof)); if (isInstanceof) { - return MMap(ctxx, jsValue); + return MMap(ctxx, jsValue); } NAPI_CHECK_FATAL(napi_is_set(env, jsValue, &isInstanceof)); if (isInstanceof) { - return MSet(ctxx, jsValue); + return MSet(ctxx, jsValue); } NAPI_CHECK_FATAL(napi_is_promise(env, jsValue, &isInstanceof)); if (isInstanceof) { @@ -391,11 +397,11 @@ private: } NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof)); if (isInstanceof) { - return MError(ctxx, jsValue); + return MError(ctxx, jsValue); } NAPI_CHECK_FATAL(napi_is_date(env, jsValue, &isInstanceof)); if (isInstanceof) { - return MDate(ctxx, jsValue); + return MDate(ctxx, jsValue); } if (IsConstructor(env, jsValue, CONSTRUCTOR_NAME_NUMBER)) { return BuiltinConvert(ctxx, env, jsValue); @@ -414,6 +420,8 @@ private: napi_env env = ctxx->GetJSEnv(); (void)verified; // ignored for Object + auto coro = EtsCoroutine::GetCurrent(); + ScopedNativeCodeThread nativeScope(coro); napi_valuetype jsType = GetValueType(env, jsValue); switch (jsType) { case napi_boolean: @@ -433,6 +441,7 @@ private: case napi_external: return BuiltinConvert(ctxx, env, jsValue); case napi_function: { + ScopedManagedCodeThread managedScope(coro); auto refconv = JSRefConvertResolve(ctxx, PlatformTypes()->coreFunction->GetRuntimeClass()); ASSERT(refconv != nullptr); return EtsObject::FromCoreType(refconv->Unwrap(ctxx, jsValue)->GetCoreType()); diff --git a/static_core/plugins/ets/runtime/interop_js/js_refconvert_record.cpp b/static_core/plugins/ets/runtime/interop_js/js_refconvert_record.cpp index 2291fc0064..b5c4a0a658 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_refconvert_record.cpp +++ b/static_core/plugins/ets/runtime/interop_js/js_refconvert_record.cpp @@ -118,7 +118,7 @@ napi_value JSRefConvertRecord::RecordSetHandler(napi_env env, napi_callback_info CallETSInstance(coro, ctx, setMethod, sp, etsThis); - napi_value trueValue = GetBooleanValue(env, true); + napi_value trueValue = GetBoolean(env, true); return trueValue; } diff --git a/static_core/plugins/ets/runtime/interop_js/js_value.cpp b/static_core/plugins/ets/runtime/interop_js/js_value.cpp index 5f0fc3b26c..c99e55ecf3 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_value.cpp +++ b/static_core/plugins/ets/runtime/interop_js/js_value.cpp @@ -14,6 +14,7 @@ */ #include "plugins/ets/runtime/interop_js/js_value.h" +#include "ets_coroutine.h" #include "plugins/ets/runtime/interop_js/js_convert.h" #include "plugins/ets/runtime/types/ets_method.h" #include "runtime/mem/local_object_handle.h" @@ -127,7 +128,7 @@ JSValue *JSValue::CreateByType(InteropCtx *ctx, napi_env env, napi_value nvalue, JSValue *JSValue::Create(EtsCoroutine *coro, InteropCtx *ctx, napi_value nvalue) { auto env = ctx->GetJSEnv(); - napi_valuetype jsType = GetValueType(env, nvalue); + napi_valuetype jsType = GetValueType(env, nvalue); auto jsvalue = AllocUndefined(coro, ctx); if (UNLIKELY(jsvalue == nullptr)) { @@ -137,10 +138,9 @@ JSValue *JSValue::Create(EtsCoroutine *coro, InteropCtx *ctx, napi_value nvalue) return CreateByType(ctx, env, nvalue, jsType, jsvalue); } -napi_value JSValue::GetNapiValue(napi_env env) +napi_value JSValue::DoGetNapiValue(napi_env env) { napi_value jsValue {}; - auto jsType = GetType(); switch (jsType) { case napi_undefined: { @@ -185,4 +185,18 @@ napi_value JSValue::GetNapiValue(napi_env env) UNREACHABLE(); } +template +napi_value JSValue::GetNapiValue(napi_env env) +{ + if constexpr (IS_IN_NATIVE) { + ScopedNativeCodeThread nativeScope(EtsCoroutine::GetCurrent()); + return DoGetNapiValue(env); + } + return DoGetNapiValue(env);; +} + +// Explicit instantiation +template napi_value JSValue::GetNapiValue(napi_env); +template napi_value JSValue::GetNapiValue(napi_env); + } // namespace ark::ets::interop::js diff --git a/static_core/plugins/ets/runtime/interop_js/js_value.h b/static_core/plugins/ets/runtime/interop_js/js_value.h index 71209efa71..fefe363c3c 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_value.h +++ b/static_core/plugins/ets/runtime/interop_js/js_value.h @@ -16,6 +16,7 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JSVALUE_H_ #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JSVALUE_H_ +#include "include/thread_scopes.h" #include "plugins/ets/runtime/ets_coroutine.h" #include "plugins/ets/runtime/interop_js/interop_common.h" #include "plugins/ets/runtime/interop_js/interop_context.h" @@ -125,8 +126,11 @@ public: } // prefer JSConvertJSValue::WrapWithNullCheck + template napi_value GetNapiValue(napi_env env); + napi_value DoGetNapiValue(napi_env env); + bool GetBoolean() const { ASSERT(GetType() == napi_boolean); @@ -344,7 +348,7 @@ private: ASSERT(GetValueType(ctx->GetJSEnv(), jsValue) == type); ASSERT(IsRefType(type)); SetType(type); - SetData(ctx->GetSharedRefStorage()->CreateJSObjectRef(ctx, this, jsValue)); + SetData(ctx->GetSharedRefStorage()->CreateJSObjectRef(ctx, this, jsValue)); } FIELD_UNUSED uint32_t type_; diff --git a/static_core/plugins/ets/runtime/interop_js/xref_object_operator.cpp b/static_core/plugins/ets/runtime/interop_js/xref_object_operator.cpp index c76b53e621..27e4dcd6a9 100644 --- a/static_core/plugins/ets/runtime/interop_js/xref_object_operator.cpp +++ b/static_core/plugins/ets/runtime/interop_js/xref_object_operator.cpp @@ -17,6 +17,7 @@ #include +#include "objects/base_type.h" #include "plugins/ets/runtime/ets_coroutine.h" #include "plugins/ets/runtime/interop_js/code_scopes.h" #include "plugins/ets/runtime/interop_js/interop_common.h" @@ -54,8 +55,12 @@ EtsObject *XRefObjectOperator::GetProperty(EtsCoroutine *coro, const std::string auto env = ctx->GetJSEnv(); napi_value jsThis = this->GetNapiValue(coro); - auto resultTaggedType = - common::DynamicObjectAccessorUtil::GetProperty(ArkNapiHelper::ToBaseObject(jsThis), name.c_str()); + common::TaggedType *resultTaggedType = nullptr; + { + ScopedNativeCodeThread nativeScope(coro); + resultTaggedType = + common::DynamicObjectAccessorUtil::GetProperty(ArkNapiHelper::ToBaseObject(jsThis), name.c_str()); + } if (NapiIsExceptionPending(env)) { ctx->ForwardJSException(coro); return {}; diff --git a/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp b/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp index c61d5c6dbf..ff4526f6b4 100644 --- a/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp +++ b/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp @@ -550,10 +550,10 @@ static void RefReverse(void *arrAddr, int32_t length, mem::GCBarrierSet *barrier } swap(aPtr, bPtr); }; - auto putSafepoint = [&usePreBarrier, barrierSet, arr](size_t dstStart, size_t dstEndMirror, size_t length) { + auto putSafepoint = [&usePreBarrier, barrierSet, arr](size_t dstStart, size_t dstEndMirror, size_t dstLength) { if (barrierSet->GetPostType() != ark::mem::BarrierType::POST_WRB_NONE) { constexpr uint32_t OFFSET = ark::coretypes::Array::GetDataOffset(); - const uint32_t size = length * sizeof(ObjectPointerType); + const uint32_t size = dstLength * sizeof(ObjectPointerType); barrierSet->PostBarrier(arr, OFFSET + dstStart * sizeof(ObjectPointerType), size); barrierSet->PostBarrier(arr, OFFSET + dstEndMirror * sizeof(ObjectPointerType) - size, size); } diff --git a/static_core/plugins/ets/tests/interop_js/tests/concurrency/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/concurrency/CMakeLists.txt index 16e059bc13..876ee81b4a 100644 --- a/static_core/plugins/ets/tests/interop_js/tests/concurrency/CMakeLists.txt +++ b/static_core/plugins/ets/tests/interop_js/tests/concurrency/CMakeLists.txt @@ -11,5 +11,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_subdirectory(ts_to_ets) +#add_subdirectory(ts_to_ets) -- Gitee From 7bfa16e8ed5490d5d43011f260c82a60d1986c4c Mon Sep 17 00:00:00 2001 From: weibaoxiang Date: Wed, 10 Sep 2025 20:16:02 +0800 Subject: [PATCH 2/2] test Change-Id: I78044e60008e445fe962c44df0e1311b829dd692 --- common_interfaces/objects/base_class.h | 25 +++- .../objects/dynamic_object_accessor_util.h | 9 +- .../ets/runtime/ets_platform_types.cpp | 8 + .../plugins/ets/runtime/ets_platform_types.h | 8 + .../runtime/interop_js/interop_context.cpp | 140 ++++++++++++++++++ .../ets/runtime/interop_js/interop_context.h | 34 +++++ .../ets/runtime/interop_js/js_convert_base.h | 22 ++- .../interop_js/js_refconvert_builtin.cpp | 33 +---- .../interop_js/napi_impl/ark_napi_helper.h | 93 +++++++++++- .../plugins/ets/runtime/types/ets_bigint.h | 5 + .../plugins/ets/runtime/types/ets_object.h | 5 + 11 files changed, 337 insertions(+), 45 deletions(-) diff --git a/common_interfaces/objects/base_class.h b/common_interfaces/objects/base_class.h index f7e9103ca2..636f636f3a 100644 --- a/common_interfaces/objects/base_class.h +++ b/common_interfaces/objects/base_class.h @@ -33,6 +33,27 @@ enum class ObjectType : uint8_t { STRING_FIRST = LINE_STRING, STRING_LAST = TREE_STRING, + + JS_FUNCTION = 10, + JS_ERROR = 31, + JS_EVAL_ERROR = 32, + JS_RANGE_ERROR = 33, + JS_REFERENCE_ERROR = 34, + JS_TYPE_ERROR = 35, + JS_AGGREGATE_ERROR = 36, + JS_URI_ERROR = 37, + JS_SYNTAX_ERROR = 38, + JS_OOM_ERROR = 39, + JS_TERMINATION_ERROR = 40, + JS_SET = 42, + JS_MAP = 44, + JS_DATE = 50, + JS_MAP_ITERATOR = 55, + JS_SET_ITERATOR = 57, + JS_PROMISE = 93, + JS_ARRAY = 99, + JS_PRIMITIVE_REF = 141, + BIGINT = 150, }; class BaseClass { @@ -45,7 +66,7 @@ public: using HeaderType = uint64_t; static constexpr size_t TYPE_BITFIELD_NUM = common::BITS_PER_BYTE * sizeof(ObjectType); - using ObjectTypeBits = common::BitField; // 8 + using ObjectTypeBits = common::BitField; // 8 ObjectType GetObjectType() const { @@ -91,4 +112,4 @@ private: uint64_t bitfield_; }; } // namespace common -#endif //COMMON_INTERFACE_OBJECTS_BASE_CLASS_H +#endif // COMMON_INTERFACE_OBJECTS_BASE_CLASS_H \ No newline at end of file diff --git a/common_interfaces/objects/dynamic_object_accessor_util.h b/common_interfaces/objects/dynamic_object_accessor_util.h index a338a1efcb..cf23b017ec 100644 --- a/common_interfaces/objects/dynamic_object_accessor_util.h +++ b/common_interfaces/objects/dynamic_object_accessor_util.h @@ -16,6 +16,7 @@ #ifndef COMMON_INTERFACES_OBJECTS_BASE_OBJECT_ACCESSOR_UTIL_H #define COMMON_INTERFACES_OBJECTS_BASE_OBJECT_ACCESSOR_UTIL_H +#include "objects/base_class.h" #include "objects/base_object.h" #include "objects/base_type.h" @@ -24,13 +25,17 @@ namespace common { // Will switch to dynamicObjectAccessor interfaces after hybrid VM and CMC is fixed. class PUBLIC_API DynamicObjectAccessorUtil { public: + __attribute__((weak)) static bool IsInstanceOf(const BaseObject *checkObj, const BaseObject *targetObj); + + __attribute__((weak)) static ObjectType GetObjectType(const BaseObject *obj); + // GetProperty is used to get the value of a property from a dynamic object with the given name. - __attribute__((weak)) static TaggedType* GetProperty(const BaseObject *obj, const char *name); + __attribute__((weak)) static TaggedType *GetProperty(const BaseObject *obj, const char *name); // SetProperty is used to set the value of a property in a dynamic object with the given name. __attribute__((weak)) static bool SetProperty(const BaseObject *obj, const char *name, TaggedType value); - __attribute__((weak)) static TaggedType* CallFunction(TaggedType jsThis, TaggedType function, int32_t argc, + __attribute__((weak)) static TaggedType *CallFunction(TaggedType jsThis, TaggedType function, int32_t argc, TaggedType *argv); }; } // namespace common diff --git a/static_core/plugins/ets/runtime/ets_platform_types.cpp b/static_core/plugins/ets/runtime/ets_platform_types.cpp index ac3cdaa495..cc5d4d4847 100644 --- a/static_core/plugins/ets/runtime/ets_platform_types.cpp +++ b/static_core/plugins/ets/runtime/ets_platform_types.cpp @@ -166,6 +166,11 @@ EtsPlatformTypes::EtsPlatformTypes([[maybe_unused]] EtsCoroutine *coro) findType(&EtsPlatformTypes::escompatBigint, BIG_INT); findType(&EtsPlatformTypes::escompatError, ERROR); + findType(&EtsPlatformTypes::escompatRangeError, RANGE_ERROR); + findType(&EtsPlatformTypes::escompatReferenceError, REFERENCE_ERROR); + findType(&EtsPlatformTypes::escompatSyntaxError, SYNTAX_ERROR); + findType(&EtsPlatformTypes::escompatURIError, URI_ERROR); + findType(&EtsPlatformTypes::escompatTypeError, TYPE_ERROR); findType(&EtsPlatformTypes::coreFunction, FUNCTION); for (size_t i = 0; i < coreFunctions.size(); ++i) { @@ -255,7 +260,10 @@ EtsPlatformTypes::EtsPlatformTypes([[maybe_unused]] EtsCoroutine *coro) CreateAndInitializeCaches(); } + findType(&EtsPlatformTypes::escompatDate, DATE); + findType(&EtsPlatformTypes::escompatSet, SET); findType(&EtsPlatformTypes::escompatMap, MAP); + findType(&EtsPlatformTypes::escompatMapIterator, MAPITERATOR); findType(&EtsPlatformTypes::escompatMapEntry, MAPENTRY); } diff --git a/static_core/plugins/ets/runtime/ets_platform_types.h b/static_core/plugins/ets/runtime/ets_platform_types.h index ad7f0473a9..3457bffd23 100644 --- a/static_core/plugins/ets/runtime/ets_platform_types.h +++ b/static_core/plugins/ets/runtime/ets_platform_types.h @@ -58,6 +58,11 @@ public: /* ets base language classes */ EtsClass *escompatBigint {}; EtsClass *escompatError {}; + EtsClass *escompatRangeError {}; + EtsClass *escompatReferenceError {}; + EtsClass *escompatSyntaxError {}; + EtsClass *escompatURIError {}; + EtsClass *escompatTypeError {}; EtsClass *coreFunction {}; std::array coreFunctions {}; std::array coreFunctionRs {}; @@ -151,7 +156,10 @@ public: } Entry const *GetTypeEntry(const uint8_t *descriptor) const; + EtsClass *escompatDate {}; + EtsClass *escompatSet {}; EtsClass *escompatMap {}; + EtsClass *escompatMapIterator {}; EtsClass *escompatMapEntry {}; public: diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp index d7f8506df3..38e6cfb044 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp +++ b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp @@ -14,6 +14,7 @@ */ #include "plugins/ets/runtime/interop_js/interop_context.h" +#include "objects/base_class.h" #include "plugins/ets/runtime/interop_js/interop_context_api.h" #include "plugins/ets/runtime/ets_exceptions.h" @@ -930,4 +931,143 @@ bool CreateMainInteropContext(ark::ets::EtsCoroutine *mainCoro, void *napiEnv) #endif } +TaggedType *InteropCtx::GetPrimitiveValue(InteropCtx *ctx, napi_value jsValue) +{ + auto coro = EtsCoroutine::GetCurrent(); + using common::DynamicObjectAccessorUtil; + auto valueOfFunc = DynamicObjectAccessorUtil::GetProperty(ArkNapiHelper::ToBaseObject(jsValue), "valueOf"); + auto retVal = + DynamicObjectAccessorUtil::CallFunction(ArkNapiHelper::GetTaggedType(jsValue), *valueOfFunc, 0, nullptr); + + if (NapiIsExceptionPending(ctx->GetJSEnv())) { + ctx->ForwardJSException(coro); + return nullptr; + } + return retVal; +} + +EtsObject *InteropCtx::ConvertToStaticBigint(EtsCoroutine *coro, napi_value val) +{ + napi_env env = this->GetJSEnv(); + auto [words, signBit] = GetBigInt(env, val); + std::vector array = ConvertBigIntArrayFromJsToEts(words); + + auto *etsIntArray = EtsIntArray::Create(array.size()); + ASSERT(etsIntArray != nullptr); + for (uint32_t i = 0; i < array.size(); ++i) { + etsIntArray->Set(i, array[i]); + } + + [[maybe_unused]] EtsHandleScope scope(coro); + EtsHandle etsIntArrayHandle(coro, etsIntArray); + + auto bigintKlass = EtsClass::FromRuntimeClass(this->GetBigIntClass()); + auto bigInt = EtsBigInt::FromEtsObject(EtsObject::Create(bigintKlass)); + bigInt->SetFieldObject(EtsBigInt::GetBytesOffset(), reinterpret_cast(etsIntArrayHandle.GetPtr())); + bigInt->SetFieldPrimitive(EtsBigInt::GetSignOffset(), array.empty() ? 0 : signBit == 0 ? 1 : -1); + + return bigInt->AsObject(); +} + +EtsObject *InteropCtx::ConvertToStaticBuiltin(EtsCoroutine *coro, napi_value val) +{ + using common::ObjectType; + auto type = common::DynamicObjectAccessorUtil::GetObjectType(ArkNapiHelper::ToBaseObject(val)); + EtsClass *sourceClass = nullptr; + auto platformTypes = PlatformTypes(coro); + switch (type) { + case ObjectType::LINE_STRING: + case ObjectType::SLICED_STRING: + case ObjectType::TREE_STRING: { + return ConvertToStaticString(val); + } + case ObjectType::JS_FUNCTION: { + return ConvertToStaticFunction(platformTypes, val); + } + case ObjectType::JS_ERROR: + case ObjectType::JS_EVAL_ERROR: + sourceClass = platformTypes->escompatError; + break; + case ObjectType::JS_RANGE_ERROR: + sourceClass = platformTypes->escompatRangeError; + break; + case ObjectType::JS_REFERENCE_ERROR: + sourceClass = platformTypes->escompatReferenceError; + break; + case ObjectType::JS_TYPE_ERROR: + sourceClass = platformTypes->escompatTypeError; + break; + case ObjectType::JS_AGGREGATE_ERROR: + sourceClass = platformTypes->escompatError; + break; + case ObjectType::JS_URI_ERROR: + sourceClass = platformTypes->escompatURIError; + break; + case ObjectType::JS_SYNTAX_ERROR: + sourceClass = platformTypes->escompatSyntaxError; + break; + case ObjectType::JS_OOM_ERROR: + case ObjectType::JS_TERMINATION_ERROR: + sourceClass = platformTypes->escompatError; + break; + case ObjectType::JS_SET: + sourceClass = platformTypes->escompatSet; + break; + case ObjectType::JS_MAP: + sourceClass = platformTypes->escompatMap; + break; + case ObjectType::JS_DATE: + sourceClass = platformTypes->escompatDate; + break; + case ObjectType::JS_PROMISE: { + return ConvertToStaticPromise(val); + } + case ObjectType::JS_ARRAY: + sourceClass = platformTypes->escompatArray; + break; + case ObjectType::JS_PRIMITIVE_REF: { + return ConvertToStaticPrimitiveRef(val); + } + case ObjectType::BIGINT: { + return ConvertToStaticBigint(coro, val); + } + default: + return JSValue::Create(EtsCoroutine::GetCurrent(), this, val)->AsObject(); + } + auto convertor = GetEtsClassWrappersCache()->Lookup(sourceClass); + ASSERT(convertor != nullptr); + return convertor->CreateJSBuiltinProxy(this, val); +} + +EtsObject *InteropCtx::ConvertToStatic(napi_value val) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto jsTaggedType = ArkNapiHelper::GetTaggedType(val); + if (ArkNapiHelper::IsUndefined(jsTaggedType)) { + return nullptr; + } + if (ArkNapiHelper::IsNull(jsTaggedType)) { + return GetNullValue(); + } + if (ArkNapiHelper::IsTrue(jsTaggedType)) { + return EtsBoxPrimitive::Create(coro, ToEtsBoolean(true)); + } + if (ArkNapiHelper::IsFalse(jsTaggedType)) { + return EtsBoxPrimitive::Create(coro, ToEtsBoolean(false)); + } + if (ArkNapiHelper::IsDouble(jsTaggedType)) { + return EtsBoxPrimitive::Create(coro, ArkNapiHelper::ToNumberFromDouble(jsTaggedType)); + } + if (ArkNapiHelper::IsInt(jsTaggedType)) { + return EtsBoxPrimitive::Create(coro, ArkNapiHelper::ToNumberFromInt(jsTaggedType)); + } + if (ArkNapiHelper::IsHeapObject(jsTaggedType)) { + auto sharedRef = GetSharedRefStorage()->GetReference(GetJSEnv(), val); + if (sharedRef != nullptr) { + return sharedRef->GetEtsObject(); + } + return ConvertToStaticBuiltin(coro, val); + } + UNREACHABLE(); +} } // namespace ark::ets::interop::js diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.h b/static_core/plugins/ets/runtime/interop_js/interop_context.h index 4aee4e5e10..930f67485f 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_context.h +++ b/static_core/plugins/ets/runtime/interop_js/interop_context.h @@ -17,6 +17,7 @@ #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_CONTEXT_H_ #include "ets_platform_types.h" +#include "interop_js/napi_impl/ark_napi_helper.h" #include "plugins/ets/runtime/ets_coroutine.h" #include "plugins/ets/runtime/ets_vm.h" #include "plugins/ets/runtime/interop_js/app_state_manager.h" @@ -460,6 +461,8 @@ public: Fatal(msg.c_str()); } + static TaggedType *GetPrimitiveValue(InteropCtx *ctx, napi_value jsValue); + void SetPendingNewInstance(EtsHandle handle) { pendingNewInstance_ = handle; @@ -487,6 +490,8 @@ public: return sharedEtsVmState_->etsProxyRefStorage.get(); } + EtsObject *ConvertToStatic(napi_value val); + EtsObject *GetNullValue() const { return EtsObject::FromCoreType(GetPandaEtsVM()->GetNullValue()); @@ -627,6 +632,35 @@ private: PandaUniquePtr ecmaVMIterfaceAdaptor_; + inline EtsObject *ConvertToStaticString(napi_value val) + { + std::string value = GetString(GetJSEnv(), val); + return EtsString::CreateFromUtf8(value.data(), value.length())->AsObject(); + } + + inline EtsObject *ConvertToStaticFunction(const EtsPlatformTypes *platformTypes, napi_value val) + { + auto refconv = JSRefConvertResolve(this, platformTypes->coreFunction->GetRuntimeClass()); + ASSERT(refconv != nullptr); + return EtsObject::FromCoreType(refconv->Unwrap(this, val)->GetCoreType()); + } + + inline EtsObject *ConvertToStaticPromise(napi_value val) + { + auto refconv = JSRefConvertResolve(this, GetPromiseClass()); + ASSERT(refconv != nullptr); + return EtsObject::FromCoreType(refconv->Unwrap(this, val)->GetCoreType()); + } + + EtsObject *ConvertToStaticBigint(EtsCoroutine *coro, napi_value val); + + inline EtsObject *ConvertToStaticPrimitiveRef(napi_value val) + { + return ConvertToStatic(ArkNapiHelper::ToNapiValue(GetPrimitiveValue(this, val))); + } + + EtsObject *ConvertToStaticBuiltin(EtsCoroutine *coro, napi_value val); + // Allocator calls our protected ctor friend class mem::Allocator; diff --git a/static_core/plugins/ets/runtime/interop_js/js_convert_base.h b/static_core/plugins/ets/runtime/interop_js/js_convert_base.h index be713c8012..e2c37afb62 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_convert_base.h +++ b/static_core/plugins/ets/runtime/interop_js/js_convert_base.h @@ -16,6 +16,8 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H +#include "interop_js/napi_impl/ark_napi_helper.h" +#include "objects/dynamic_object_accessor_util.h" #include "plugins/ets/runtime/ets_panda_file_items.h" #include "plugins/ets/runtime/interop_js/interop_common.h" #include "plugins/ets/runtime/interop_js/js_value.h" @@ -58,11 +60,11 @@ inline void JSConvertTypeCheckFailed(const std::string &s) static bool DoIsConstructor(napi_env &env, napi_value &jsValue, const char *constructorName) { - napi_value constructor; - bool isInstanceof; - NAPI_CHECK_FATAL(napi_get_named_property(env, GetGlobal(env), constructorName, &constructor)); - NAPI_CHECK_FATAL(napi_instanceof(env, jsValue, constructor, &isInstanceof)); - return isInstanceof; + using namespace common; + auto cTaggedType = + DynamicObjectAccessorUtil::GetProperty(ArkNapiHelper::ToBaseObject(GetGlobal(env)), constructorName); + return DynamicObjectAccessorUtil::IsInstanceOf( + ArkNapiHelper::ToBaseObject(jsValue), ArkNapiHelper::ToBaseObject(ArkNapiHelper::ToNapiValue(cTaggedType))); } template @@ -81,9 +83,13 @@ static bool DoGetValueByValueOf(napi_env env, napi_value &jsValue, const char *c if (!IsConstructor(env, jsValue, constructorName)) { return false; } - napi_value method; - NAPI_CHECK_FATAL(napi_get_named_property(env, jsValue, "valueOf", &method)); - NAPI_CHECK_FATAL(napi_call_function(env, jsValue, method, 0, nullptr, result)); + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + auto resultTaggedType = InteropCtx::GetPrimitiveValue(ctx, jsValue); + if (resultTaggedType == nullptr) { + return false; + } + *result = ArkNapiHelper::ToNapiValue(resultTaggedType); return true; } diff --git a/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp b/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp index 2d30d28452..24452744ad 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp +++ b/static_core/plugins/ets/runtime/interop_js/js_refconvert_builtin.cpp @@ -417,39 +417,8 @@ private: EtsObject *MObject(InteropCtx *ctxx, napi_value jsValue, bool verified = true) { - napi_env env = ctxx->GetJSEnv(); (void)verified; // ignored for Object - - auto coro = EtsCoroutine::GetCurrent(); - ScopedNativeCodeThread nativeScope(coro); - napi_valuetype jsType = GetValueType(env, jsValue); - switch (jsType) { - case napi_boolean: - return BuiltinConvert(ctxx, env, jsValue); - case napi_number: - return BuiltinConvert(ctxx, env, jsValue); - case napi_string: - return BuiltinConvert(ctxx, env, jsValue); - case napi_object: - return MObjectObject(ctx_, jsValue); - case napi_null: - return ctx_->GetNullValue(); - case napi_bigint: - return BuiltinConvert(ctxx, env, jsValue); - case napi_symbol: - [[fallthrough]]; - case napi_external: - return BuiltinConvert(ctxx, env, jsValue); - case napi_function: { - ScopedManagedCodeThread managedScope(coro); - auto refconv = JSRefConvertResolve(ctxx, PlatformTypes()->coreFunction->GetRuntimeClass()); - ASSERT(refconv != nullptr); - return EtsObject::FromCoreType(refconv->Unwrap(ctxx, jsValue)->GetCoreType()); - } - default: - ASSERT(!IsNullOrUndefined(env, jsValue)); - InteropCtx::Fatal("Bad jsType in Object value matcher"); - }; + return ctxx->ConvertToStatic(jsValue); } public: diff --git a/static_core/plugins/ets/runtime/interop_js/napi_impl/ark_napi_helper.h b/static_core/plugins/ets/runtime/interop_js/napi_impl/ark_napi_helper.h index e9250acc18..19a2214434 100644 --- a/static_core/plugins/ets/runtime/interop_js/napi_impl/ark_napi_helper.h +++ b/static_core/plugins/ets/runtime/interop_js/napi_impl/ark_napi_helper.h @@ -16,8 +16,10 @@ #ifndef PANDA_ARK_NAPI_HELPER_H #define PANDA_ARK_NAPI_HELPER_H -#include #include "objects/base_type.h" +#include "plugins/ets/runtime/interop_js/logger.h" +#include +#include "utils/bit_utils.h" namespace ark::ets::interop::js { @@ -26,6 +28,49 @@ using common::TaggedType; class PUBLIC_API ArkNapiHelper { public: + static constexpr size_t TAG_BITS_SHIFT = 48; + static constexpr TaggedType TAG_MARK = 0xFFFFULL << TAG_BITS_SHIFT; + // int tag + static constexpr TaggedType TAG_INT = TAG_MARK; + static constexpr TaggedType TAG_INT32_INC_MAX = INT32_MAX + 1ULL; + static constexpr TaggedType TAG_INT32_DEC_MIN = INT32_MIN - 1ULL; + // object tag + static constexpr TaggedType TAG_OBJECT = 0x0000ULL << TAG_BITS_SHIFT; + // weak object tag + static constexpr TaggedType TAG_WEAK = TAG_OBJECT | 0x01ULL; + // special tag + static constexpr TaggedType TAG_NULL = 0x01ULL; + static constexpr TaggedType TAG_SPECIAL = 0x02ULL; + static constexpr TaggedType TAG_BOOLEAN = 0x04ULL; + static constexpr TaggedType TAG_EXCEPTION = 0x08ULL; + static constexpr TaggedType TAG_OPTIMIZED_OUT = 0x12ULL; + // tag mask + static constexpr TaggedType TAG_SPECIAL_MASK = TAG_MARK | TAG_SPECIAL; + static constexpr TaggedType TAG_BOOLEAN_MASK = TAG_SPECIAL | TAG_BOOLEAN; + static constexpr TaggedType TAG_HEAPOBJECT_MASK = TAG_MARK | TAG_SPECIAL | TAG_BOOLEAN; + static constexpr TaggedType TAG_WEAK_MASK = TAG_HEAPOBJECT_MASK | TAG_WEAK; + // special value + static constexpr TaggedType VALUE_HOLE = 0x05ULL; + static constexpr TaggedType VALUE_NULL = TAG_OBJECT | TAG_SPECIAL | TAG_NULL; + static constexpr TaggedType VALUE_FALSE = TAG_BOOLEAN_MASK | static_cast(false); + static constexpr TaggedType VALUE_TRUE = TAG_BOOLEAN_MASK | static_cast(true); + static constexpr TaggedType VALUE_UNDEFINED = TAG_SPECIAL; + static constexpr TaggedType VALUE_EXCEPTION = TAG_SPECIAL | TAG_EXCEPTION; + static constexpr TaggedType VALUE_ZERO = TAG_INT | 0x00ULL; + static constexpr TaggedType VALUE_OPTIMIZED_OUT = TAG_SPECIAL | TAG_OPTIMIZED_OUT; + // ReadBarrier DFX tag + static constexpr size_t TAG_READ_BARRIER_SHIFT = 47; + static constexpr TaggedType TAG_READ_BARRIER_DFX = 0x1ULL << TAG_READ_BARRIER_SHIFT; + static constexpr TaggedType TAG_READ_BARRIER_DFX_MASK = TAG_HEAPOBJECT_MASK | TAG_READ_BARRIER_DFX; + + static constexpr size_t INT_SIGN_BIT_OFFSET = 31; + static constexpr size_t DOUBLE_ENCODE_OFFSET_BIT = 48; + static constexpr TaggedType DOUBLE_ENCODE_OFFSET = 1ULL << DOUBLE_ENCODE_OFFSET_BIT; + // Tagged +0.0 = IEEE754 representation of +0.0 + offset + static constexpr TaggedType VALUE_POSITIVE_ZERO = 0x0000'0000'0000'0000ULL + DOUBLE_ENCODE_OFFSET; + // Tagged -0.0 = IEEE754 representation of -0.0 + offset + static constexpr TaggedType VALUE_NEGATIVE_ZERO = 0x8000'0000'0000'0000ULL + DOUBLE_ENCODE_OFFSET; + static inline TaggedType GetTaggedType([[maybe_unused]] napi_value napiValue) { #if defined(PANDA_TARGET_OHOS) || defined(PANDA_JS_ETS_HYBRID_MODE) @@ -50,6 +95,52 @@ public: return nullptr; #endif } + + static inline bool IsFalse(TaggedType val) + { + return val == VALUE_FALSE; + } + + static inline bool IsTrue(TaggedType val) + { + return val == VALUE_TRUE; + } + + static inline bool IsUndefined(TaggedType val) + { + return val == VALUE_UNDEFINED; + } + + static inline bool IsNull(TaggedType val) + { + return val == VALUE_NULL; + } + + static inline bool IsHeapObject(TaggedType val) + { + return (val & TAG_HEAPOBJECT_MASK) == 0U; + } + + static inline bool IsInt(TaggedType val) + { + return (val & TAG_MARK) == TAG_INT; + } + + static inline bool IsDouble(TaggedType val) + { + auto tmp = val & TAG_MARK; + return tmp != TAG_INT && tmp != TAG_OBJECT; + } + + static inline double ToNumberFromDouble(TaggedType val) + { + return bit_cast(val - DOUBLE_ENCODE_OFFSET); + } + + static inline double ToNumberFromInt(TaggedType val) + { + return static_cast(val & (~TAG_MARK)); + } }; } // namespace ark::ets::interop::js #endif // PANDA_ARK_NAPI_HELPER_H \ No newline at end of file diff --git a/static_core/plugins/ets/runtime/types/ets_bigint.h b/static_core/plugins/ets/runtime/types/ets_bigint.h index bf10dfe79e..4e786679a9 100644 --- a/static_core/plugins/ets/runtime/types/ets_bigint.h +++ b/static_core/plugins/ets/runtime/types/ets_bigint.h @@ -33,6 +33,11 @@ public: return reinterpret_cast(etsObj); } + EtsObject *AsObject() + { + return reinterpret_cast(this); + } + /* The sign field can have the following values: -1, 0, 1 * -1 - for negative * 0 - for zero value diff --git a/static_core/plugins/ets/runtime/types/ets_object.h b/static_core/plugins/ets/runtime/types/ets_object.h index 9ddad73cd8..1b44efdf15 100644 --- a/static_core/plugins/ets/runtime/types/ets_object.h +++ b/static_core/plugins/ets/runtime/types/ets_object.h @@ -36,6 +36,11 @@ public: PANDA_PUBLIC_API static EtsObject *Create(EtsClass *klass); + PANDA_PUBLIC_API ObjectHeader *AsObjectHeader() + { + return static_cast(this); + } + PANDA_PUBLIC_API EtsClass *GetClass() const { return EtsClass::FromRuntimeClass(GetCoreType()->ClassAddr()); -- Gitee