1 /**
2 * Copyright (c) 2025 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 "arkts_esvalue.h"
17
18 #include <node_api.h>
19
20 #include "plugins/ets/runtime/ani/scoped_objects_fix.h"
21 #include "plugins/ets/runtime/ets_napi_env.h"
22 #include "plugins/ets/runtime/interop_js/code_scopes.h"
23 #include "plugins/ets/runtime/interop_js/interop_context.h"
24 #include "plugins/ets/runtime/interop_js/js_convert.h"
25
26 namespace ark::ets::interop::js {
27
28 static ani_class g_esvalueClass {};
29 static ani_method g_isEcmaObjectMethod {};
30 static ani_field g_evField {};
31
CacheEsValueClass(ani_env * env)32 static bool CacheEsValueClass(ani_env *env)
33 {
34 ani_class esvalueClass {};
35 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
36 [[maybe_unused]] auto status = env->FindClass("std.interop.ESValue", &esvalueClass);
37 ASSERT(status == ANI_OK);
38 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
39 if (UNLIKELY(env->GlobalReference_Create(esvalueClass, reinterpret_cast<ani_ref *>(&g_esvalueClass)) != ANI_OK)) {
40 return false;
41 }
42 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
43 status = env->Class_FindMethod(esvalueClass, "isECMAObject", ":z", &g_isEcmaObjectMethod);
44 ASSERT(status == ANI_OK);
45 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
46 status = env->Class_FindField(esvalueClass, "ev", &g_evField);
47 ASSERT(status == ANI_OK);
48 return true;
49 }
50
InitializeGlobalOnce(ani_env * env)51 static bool InitializeGlobalOnce(ani_env *env)
52 {
53 // Guaranteed to be called once
54 static bool isInitialized = CacheEsValueClass(env);
55 return isInitialized;
56 }
57
UnwrapESValue(ani_env * env,ani_object esvalue,void ** result)58 PANDA_PUBLIC_API bool UnwrapESValue(ani_env *env, ani_object esvalue, void **result)
59 {
60 if (UNLIKELY(!InitializeGlobalOnce(env))) {
61 return false;
62 }
63
64 auto *coro = EtsCoroutine::GetCurrent();
65 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
66 if (UNLIKELY(PandaEtsNapiEnv::FromAniEnv(env)->GetEtsCoroutine() != coro)) {
67 return false;
68 }
69 auto ctx = InteropCtx::Current(coro);
70 if (ctx == nullptr) {
71 return false;
72 }
73
74 ani_boolean isEsValue = ANI_FALSE;
75 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
76 [[maybe_unused]] auto status = env->Object_InstanceOf(esvalue, g_esvalueClass, &isEsValue);
77 if (status != ANI_OK || isEsValue == ANI_FALSE) {
78 return false;
79 }
80 ani_boolean isEcmaObject = ANI_FALSE;
81 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
82 status = env->Object_CallMethod_Boolean(esvalue, g_isEcmaObjectMethod, &isEcmaObject);
83 if (UNLIKELY(status != ANI_OK || isEcmaObject == ANI_FALSE)) {
84 return false;
85 }
86 ani_ref jsValue {};
87 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
88 status = env->Object_GetField_Ref(esvalue, g_evField, &jsValue);
89 ASSERT(status == ANI_OK);
90
91 ani::ScopedManagedCodeFix s(env);
92 auto *jsValueObject = JSValue::FromEtsObject(s.ToInternalType(jsValue));
93
94 INTEROP_CODE_SCOPE_ETS(coro);
95 auto jsenv = ctx->GetJSEnv();
96 NapiScope jsHandleScope(jsenv);
97
98 auto jsObj = JSConvertJSValue::WrapWithNullCheck(jsenv, jsValueObject);
99 void *res = nullptr;
100 if (napi_unwrap(jsenv, jsObj, &res) != napi_ok) {
101 return false;
102 }
103 *result = res;
104 return true;
105 }
106 } // namespace ark::ets::interop::js