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