• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef NAPI_EXPERIMENTAL
16 #define NAPI_EXPERIMENTAL
17 #endif
18 
19 #ifdef ENABLE_CONTAINER_SCOPE
20 #include "core/common/container_scope.h"
21 #endif
22 
23 #include "ecmascript/napi/include/jsnapi.h"
24 #include "ecmascript/napi/include/jsnapi_expo.h"
25 #include "native_api_internal.h"
26 #include "native_engine/impl/ark/ark_native_reference.h"
27 #include "native_engine/native_create_env.h"
28 #include "native_engine/native_utils.h"
29 #include "native_engine/worker_manager.h"
30 #include "securec.h"
31 
32 using panda::ObjectRef;
33 using panda::PropertyAttribute;
34 static constexpr char NAME_SPACE_TAG = '@';
napi_load_module_with_info_hybrid(napi_env env,const char * path,const char * module_info,napi_value * result)35 NAPI_EXTERN napi_status napi_load_module_with_info_hybrid(napi_env env,
36                                                           const char* path,
37                                                           const char* module_info,
38                                                           napi_value* result)
39 {
40     NAPI_PREAMBLE(env);
41     CHECK_ARG(env, result);
42     auto engine = reinterpret_cast<NativeEngine*>(env);
43     *result = engine->NapiLoadModuleWithInfoForHybridApp(path, module_info);
44     return GET_RETURN_STATUS(env);
45 }
46 
napi_load_module_with_module_request(napi_env env,const char * request_name,napi_value * result)47 NAPI_EXTERN napi_status napi_load_module_with_module_request(napi_env env, const char* request_name, napi_value* result)
48 {
49     NAPI_PREAMBLE(env);
50     CHECK_ARG(env, request_name);
51     CHECK_ARG(env, result);
52 
53     if (request_name[0] == NAME_SPACE_TAG) {
54         // load module with OhmUrl
55         auto [path, module_info] = panda::JSNApi::ResolveOhmUrl(request_name);
56         napi_load_module_with_info_hybrid(env, path.c_str(), module_info.c_str(), result);
57     } else {
58         napi_load_module_with_path(env, request_name, result);
59     }
60 
61     return GET_RETURN_STATUS(env);
62 }
63 
napi_set_stackinfo(napi_env env,NapiStackInfo * napi_info)64 NAPI_EXTERN napi_status napi_set_stackinfo(napi_env env, NapiStackInfo* napi_info)
65 {
66     CHECK_ARG(env, napi_info);
67     ASSERT(napi_info != nullptr);
68     panda::StackInfo info { napi_info->stackStart, napi_info->stackSize };
69     auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
70     panda::JSNApi::SetStackInfo(vm, info);
71     return napi_clear_last_error(env);
72 }
73 
napi_get_stackinfo(napi_env env,NapiStackInfo * result)74 NAPI_EXTERN napi_status napi_get_stackinfo(napi_env env, NapiStackInfo* result)
75 {
76     CHECK_ARG(env, result);
77     ASSERT(result != nullptr);
78     auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
79     auto res = panda::JSNApi::GetStackInfo(vm);
80     result->stackStart = res.stackStart;
81     result->stackSize = res.stackSize;
82     return napi_clear_last_error(env);
83 }
84 
85 #ifdef PANDA_JS_ETS_HYBRID_MODE
napi_xref_wrap(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,NapiXRefDirection ref_direction,napi_ref * result)86 NAPI_EXTERN napi_status napi_xref_wrap(napi_env env,
87                                        napi_value js_object,
88                                        void* native_object,
89                                        napi_finalize finalize_cb,
90                                        NapiXRefDirection ref_direction,
91                                        napi_ref* result)
92 {
93     NAPI_PREAMBLE(env);
94     CHECK_ARG(env, js_object);
95     CHECK_ARG(env, native_object);
96     CHECK_ARG(env, finalize_cb);
97 
98     auto nativeValue = LocalValueFromJsValue(js_object);
99     auto callback = reinterpret_cast<NapiNativeFinalize>(finalize_cb);
100     auto engine = reinterpret_cast<ArkNativeEngine*>(env);
101     auto vm = engine->GetEcmaVm();
102     panda::JsiFastNativeScope fastNativeScope(vm);
103     CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject);
104     size_t nativeBindingSize = 0;
105     auto reference = reinterpret_cast<NativeReference**>(result);
106     Local<panda::StringRef> key = panda::StringRef::GetProxyNapiWrapperString(vm);
107     NativeReference* ref = nullptr;
108     Local<panda::ObjectRef> object = JSValueRef::Undefined(vm);
109     switch (ref_direction) {
110         case NapiXRefDirection::NAPI_DIRECTION_DYNAMIC_TO_STATIC:
111             object = panda::ObjectRef::NewJSXRefObject(vm);
112             ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object);
113             break;
114         case NapiXRefDirection::NAPI_DIRECTION_STATIC_TO_DYNAMIC:
115             object = panda::ObjectRef::New(vm);
116             ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object);
117             break;
118         case NapiXRefDirection::NAPI_DIRECTION_HYBRID:
119             // Hybrid object may only exist in cross-language inherence case.
120             // To be aborted in the future according to the specification
121             HILOG_ERROR("[napi_xref_wrap] napi_direction_hybrid is not supported now!");
122             return napi_set_last_error(env, napi_invalid_arg);
123         default:
124             HILOG_ERROR("[napi_xref_wrap] invalid ref_direction!");
125             return napi_set_last_error(env, napi_invalid_arg);
126     }
127     if (reference != nullptr) {
128         *reference = ref;
129     }
130     object->SetNativePointerFieldCount(vm, 1);
131     object->SetNativePointerField(vm, 0, ref, nullptr, nullptr, nativeBindingSize);
132     panda::PropertyAttribute attr(object, true, false, true);
133     nativeObject->DefineProperty(vm, key, attr);
134     return GET_RETURN_STATUS(env);
135 }
136 
napi_xref_unwrap(napi_env env,napi_value js_object,void ** result)137 NAPI_EXTERN napi_status napi_xref_unwrap(napi_env env, napi_value js_object, void** result)
138 {
139     NAPI_PREAMBLE(env);
140     CHECK_ARG(env, js_object);
141     CHECK_ARG(env, result);
142 
143     auto nativeValue = LocalValueFromJsValue(js_object);
144     auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
145     panda::JsiFastNativeScope fastNativeScope(vm);
146     CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject);
147     Local<panda::StringRef> key = panda::StringRef::GetProxyNapiWrapperString(vm);
148     Local<panda::JSValueRef> val = nativeObject->Get(vm, key);
149     *result = nullptr;
150     if (val->IsObject(vm)) {
151         Local<panda::ObjectRef> ext(val);
152         auto ref = reinterpret_cast<NativeReference*>(ext->GetNativePointerField(vm, 0));
153         *result = ref != nullptr ? ref->GetData() : nullptr;
154     }
155 
156     return GET_RETURN_STATUS(env);
157 }
158 
napi_mark_from_object(napi_env env,napi_ref ref)159 NAPI_EXTERN napi_status napi_mark_from_object(napi_env env, napi_ref ref)
160 {
161     NAPI_PREAMBLE(env);
162     CHECK_ARG(env, ref);
163     ArkNativeReference* reference = reinterpret_cast<ArkNativeReference*>(ref);
164     reference->MarkFromObject();
165     return napi_clear_last_error(env);
166 }
167 
napi_create_xref(napi_env env,napi_value value,uint32_t initial_refcount,napi_ref * result)168 NAPI_EXTERN napi_status napi_create_xref(napi_env env, napi_value value, uint32_t initial_refcount, napi_ref* result)
169 {
170     CHECK_ENV(env);
171     CHECK_ARG(env, value);
172     CHECK_ARG(env, result);
173 
174     auto engine = reinterpret_cast<ArkNativeEngine*>(env);
175     auto ref = engine->CreateXRefReference(value, initial_refcount, false, nullptr, nullptr);
176     *result = reinterpret_cast<napi_ref>(ref);
177     return napi_clear_last_error(env);
178 }
179 
napi_get_ets_implements(napi_env env,napi_value value,napi_value * result)180 NAPI_EXTERN napi_status napi_get_ets_implements(napi_env env, napi_value value, napi_value* result)
181 {
182     NAPI_PREAMBLE(env);
183     CHECK_ARG(env, value);
184     CHECK_ARG(env, result);
185 
186     auto nativeValue = LocalValueFromJsValue(value);
187     auto engine = reinterpret_cast<NativeEngine*>(env);
188     auto vm = engine->GetEcmaVm();
189     Local<panda::JSValueRef> implementsValue = panda::JSNApi::GetImplements(vm, nativeValue);
190     *result = JsValueFromLocalValue(implementsValue);
191     return GET_RETURN_STATUS(env);
192 }
193 
napi_register_appstate_callback(napi_env env,NapiAppStateCallback callback)194 NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback)
195 {
196     CHECK_ENV(env);
197     CHECK_ARG(env, callback);
198 
199     auto* engine = reinterpret_cast<NativeEngine*>(env);
200     engine->RegisterAppStateCallback(callback);
201 
202     return napi_clear_last_error(env);
203 }
204 
napi_vm_handshake(napi_env env,void * inputIface,void ** outputIface)205 NAPI_EXTERN napi_status napi_vm_handshake(napi_env env,
206                                           [[maybe_unused]] void* inputIface,
207                                           [[maybe_unused]] void** outputIface)
208 {
209     CHECK_ENV(env);
210     CHECK_ARG(env, inputIface);
211     CHECK_ARG(env, outputIface);
212 
213     auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
214     panda::HandshakeHelper::DoHandshake(const_cast<EcmaVM*>(vm), inputIface, outputIface);
215 
216     return napi_clear_last_error(env);
217 }
218 
napi_is_alive_object(napi_env env,napi_ref ref,bool * result)219 NAPI_EXTERN napi_status napi_is_alive_object(napi_env env, napi_ref ref, bool* result)
220 {
221     NAPI_PREAMBLE(env);
222     CHECK_ARG(env, ref);
223     ArkNativeReference* reference = reinterpret_cast<ArkNativeReference*>(ref);
224     *result = reference->IsObjectAlive();
225     return napi_clear_last_error(env);
226 }
227 
napi_is_contain_object(napi_env env,napi_ref ref,bool * result)228 NAPI_EXTERN napi_status napi_is_contain_object(napi_env env, napi_ref ref, bool* result)
229 {
230     NAPI_PREAMBLE(env);
231     CHECK_ARG(env, ref);
232     ArkNativeReference* reference = reinterpret_cast<ArkNativeReference*>(ref);
233     *result = reference->IsValidHeapObject();
234     return napi_clear_last_error(env);
235 }
236 
napi_is_xref_type(napi_env env,napi_value js_object,bool * result)237 NAPI_EXTERN napi_status napi_is_xref_type(napi_env env, napi_value js_object, bool* result)
238 {
239     *result = false;
240     NAPI_PREAMBLE(env);
241     CHECK_ARG(env, js_object);
242     CHECK_ARG(env, result);
243 
244     auto nativeValue = LocalValueFromJsValue(js_object);
245     auto engine = reinterpret_cast<ArkNativeEngine*>(env);
246     auto vm = engine->GetEcmaVm();
247     CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject);
248     Local<panda::StringRef> key = panda::StringRef::GetProxyNapiWrapperString(vm);
249 
250     if (nativeObject->Has(vm, key)) {
251         *result = true;
252     }
253     return GET_RETURN_STATUS(env);
254 }
255 
napi_mark_attach_with_xref(napi_env env,napi_value js_object,void * attach_data,proxy_object_attach_cb attach_cb)256 NAPI_EXTERN napi_status napi_mark_attach_with_xref(napi_env env,
257                                                    napi_value js_object,
258                                                    void* attach_data,
259                                                    proxy_object_attach_cb attach_cb)
260 {
261     NAPI_PREAMBLE(env);
262     CHECK_ARG(env, js_object);
263     CHECK_ARG(env, attach_data);
264     CHECK_ARG(env, attach_cb);
265 
266     auto nativeValue = LocalValueFromJsValue(js_object);
267     auto engine = reinterpret_cast<ArkNativeEngine*>(env);
268     auto vm = engine->GetEcmaVm();
269     panda::JsiFastNativeScope fastNativeScope(vm);
270     CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject);
271     size_t nativeBindingSize = 0;
272     Local<panda::StringRef> key = panda::StringRef::GetProxyNapiWrapperString(vm);
273     Local<panda::ObjectRef> object = panda::ObjectRef::NewJSXRefObject(vm);
274     // Create strong reference now, will update to weak reference after interop support
275     panda::JSNApi::XRefBindingInfo* data = panda::JSNApi::XRefBindingInfo::CreateNewInstance();
276     if (data == nullptr) {
277         HILOG_ERROR("data is nullptr");
278         return napi_set_last_error(env, napi_invalid_arg);
279     }
280     data->attachXRefFunc = reinterpret_cast<void*>(attach_cb);
281     data->attachXRefData = attach_data;
282     object->SetNativePointerFieldCount(vm, 1);
283     object->SetNativePointerField(
284         vm, 0, nullptr,
285         [](void* env, void* data, void* info) {
286             panda::JSNApi::XRefBindingInfo* externalInfo = reinterpret_cast<panda::JSNApi::XRefBindingInfo*>(info);
287             delete externalInfo;
288         },
289         reinterpret_cast<void*>(data), nativeBindingSize);
290     panda::PropertyAttribute attr(object, true, false, true);
291     nativeObject->DefineProperty(vm, key, attr);
292     return GET_RETURN_STATUS(env);
293 }
294 
295 NAPI_EXTERN napi_status
napi_serialize_hybrid(napi_env env,napi_value object,napi_value transfer_list,napi_value clone_list,void ** result)296 napi_serialize_hybrid(napi_env env, napi_value object, napi_value transfer_list, napi_value clone_list, void** result)
297 {
298     CHECK_ENV(env);
299     CHECK_ARG(env, object);
300     CHECK_ARG(env, transfer_list);
301     CHECK_ARG(env, clone_list);
302     CHECK_ARG(env, result);
303 
304     auto vm = reinterpret_cast<NativeEngine*>(env)->GetEcmaVm();
305     auto nativeValue = LocalValueFromJsValue(object);
306     auto transferList = LocalValueFromJsValue(transfer_list);
307     RETURN_STATUS_IF_FALSE(env, transferList->IsUndefined() || transferList->IsJSArray(vm), napi_invalid_arg);
308     auto cloneList = LocalValueFromJsValue(clone_list);
309     RETURN_STATUS_IF_FALSE(env, cloneList->IsUndefined() || cloneList->IsJSArray(vm), napi_invalid_arg);
310     *result = panda::JSNApi::InterOpSerializeValue(vm, nativeValue, transferList, cloneList, false, false);
311 
312     return napi_clear_last_error(env);
313 }
314 
napi_deserialize_hybrid(napi_env env,void * buffer,napi_value * object)315 NAPI_EXTERN napi_status napi_deserialize_hybrid(napi_env env, void* buffer, napi_value* object)
316 {
317     CHECK_ENV(env);
318     CHECK_ARG(env, buffer);
319     CHECK_ARG(env, object);
320 
321     auto engine = reinterpret_cast<NativeEngine*>(env);
322     auto vm = engine->GetEcmaVm();
323     Local<panda::JSValueRef> res = panda::JSNApi::InterOpDeserializeValue(vm, buffer, reinterpret_cast<void*>(engine));
324     *object = JsValueFromLocalValue(res);
325 
326     return napi_clear_last_error(env);
327 }
328 
napi_wrap_with_xref(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,napi_ref * result)329 NAPI_EXTERN napi_status napi_wrap_with_xref(napi_env env,
330                                             napi_value js_object,
331                                             void* native_object,
332                                             napi_finalize finalize_cb,
333                                             napi_ref* result)
334 {
335     NAPI_PREAMBLE(env);
336     CHECK_ARG(env, js_object);
337     CHECK_ARG(env, native_object);
338     CHECK_ARG(env, finalize_cb);
339     CHECK_ARG(env, result);
340 
341     auto nativeValue = LocalValueFromJsValue(js_object);
342     auto callback = reinterpret_cast<NapiNativeFinalize>(finalize_cb);
343     auto engine = reinterpret_cast<ArkNativeEngine*>(env);
344     auto vm = engine->GetEcmaVm();
345     panda::JsiFastNativeScope fastNativeScope(vm);
346     CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject);
347     size_t nativeBindingSize = 0;
348     auto reference = reinterpret_cast<NativeReference**>(result);
349     Local<panda::StringRef> key = panda::StringRef::GetProxyNapiWrapperString(vm);
350     NativeReference* ref = nullptr;
351     Local<panda::ObjectRef> object = panda::ObjectRef::NewJSXRefObject(vm);
352     // Create strong reference now, will update to weak reference after interop support
353     ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object);
354     *reference = ref;
355     object->SetNativePointerFieldCount(vm, 1);
356     object->SetNativePointerField(vm, 0, ref, nullptr, nullptr, nativeBindingSize);
357     PropertyAttribute attr(object, true, false, true);
358     nativeObject->DefineProperty(vm, key, attr);
359     return GET_RETURN_STATUS(env);
360 }
361 
napi_setup_hybrid_environment(napi_env env)362 NAPI_EXTERN napi_status napi_setup_hybrid_environment(napi_env env)
363 {
364     NAPI_PREAMBLE(env);
365 
366     auto engine = reinterpret_cast<NativeEngine*>(env);
367     auto vm = engine->GetEcmaVm();
368     panda::JSNApi::InitHybridVMEnv(const_cast<panda::ecmascript::EcmaVM*>(vm));
369     return GET_RETURN_STATUS(env);
370 }
371 #endif // PANDA_JS_ETS_HYBRID_MODE
372