• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_
18 
19 #include "code_scopes.h"
20 #include "plugins/ets/runtime/interop_js/js_convert.h"
21 #include "plugins/ets/runtime/interop_js/interop_common.h"
22 #include "plugins/ets/runtime/interop_js/interop_context.h"
23 #include "types/ets_object.h"
24 #include "types/ets_typeapi_type.h"
25 
26 namespace ark::ets::interop::js {
27 
28 void JSRuntimeFinalizationRegistryCallback(EtsObject *cbarg);
29 JSValue *JSRuntimeNewJSValueDouble(double v);
30 JSValue *JSRuntimeNewJSValueBoolean(uint8_t v);
31 JSValue *JSRuntimeNewJSValueString(EtsString *v);
32 JSValue *JSRuntimeNewJSValueObject(EtsObject *v);
33 uint8_t JSRuntimeIsJSValue(EtsObject *v);
34 JSValue *JSRuntimeNewJSValueBigInt(EtsBigInt *v);
35 double JSRuntimeGetValueDouble(JSValue *etsJsValue);
36 uint8_t JSRuntimeGetValueBoolean(JSValue *etsJsValue);
37 EtsString *JSRuntimeGetValueString(JSValue *etsJsValue);
38 EtsObject *JSRuntimeGetValueObject(JSValue *etsJsValue, EtsClass *clsObj);
39 JSValue *JSRuntimeGetUndefined();
40 JSValue *JSRuntimeGetNull();
41 JSValue *JSRuntimeGetGlobal();
42 JSValue *JSRuntimeCreateObject();
43 JSValue *JSRuntimeCreateArray();
44 uint8_t JSRuntimeInstanceOf(JSValue *object, JSValue *ctor);
45 uint8_t JSRuntimeInstanceOfDynamic(JSValue *object, JSValue *ctor);
46 uint8_t JSRuntimeInstanceOfStatic(JSValue *etsJsValue, EtsClass *etsCls);
47 std::pair<std::string_view, std::string_view> ResolveModuleName(std::string_view module);
48 JSValue *JSRuntimeLoadModule(EtsString *module);
49 uint8_t JSRuntimeStrictEqual([[maybe_unused]] JSValue *lhs, [[maybe_unused]] JSValue *rhs);
50 uint8_t JSRuntimeHasProperty(JSValue *object, EtsString *name);
51 JSValue *JSRuntimeGetProperty(JSValue *object, JSValue *property);
52 uint8_t JSRuntimeHasPropertyJSValue(JSValue *object, JSValue *property);
53 uint8_t JSRuntimeHasElement(JSValue *object, int index);
54 uint8_t JSRuntimeHasOwnProperty(JSValue *object, EtsString *name);
55 uint8_t JSRuntimeHasOwnPropertyJSValue(JSValue *object, JSValue *property);
56 EtsString *JSRuntimeTypeOf(JSValue *object);
57 uint8_t JSRuntimeIsPromise(JSValue *object);
58 uint8_t JSRuntimeInstanceOfStaticType(JSValue *object, EtsTypeAPIType *paramType);
59 JSValue *JSRuntimeInvoke(JSValue *recv, JSValue *func, EtsArray *args);
60 JSValue *JSRuntimeInstantiate(JSValue *callable, EtsArray *args);
61 EtsString *JSValueToString(JSValue *object);
62 napi_value ToLocal(void *value);
63 void *CompilerGetJSNamedProperty(void *val, char *propStr);
64 void *CompilerGetJSProperty(void *val, void *prop);
65 void *CompilerGetJSElement(void *val, int32_t index);
66 void *CompilerJSCallCheck(void *fn);
67 void *CompilerJSNewInstance(void *fn, uint32_t argc, void *args);
68 void CreateLocalScope();
69 void CompilerDestroyLocalScope();
70 void *CompilerLoadJSConstantPool();
71 void CompilerInitJSCallClassForCtx(void *klassPtr);
72 void *CompilerConvertVoidToLocal();
73 void *CompilerConvertRefTypeToLocal(EtsObject *etsValue);
74 void PromiseInteropResolve(EtsObject *etsValue, EtsLong deferred);
75 void PromiseInteropReject(EtsObject *etsValue, EtsLong deferred);
76 EtsString *JSONStringify(JSValue *jsvalue);
77 EtsString *CompilerConvertLocalToString(void *value);
78 EtsObject *CompilerConvertLocalToRefType(void *klassPtr, void *value);
79 JSValue *JSRuntimeGetPropertyJSValueyByKey(JSValue *objectValue, JSValue *keyValue);
80 EtsEscompatArrayBuffer *TransferArrayBufferToStatic(ESValue *object);
81 EtsObject *TransferArrayBufferToDynamic(EtsEscompatArrayBuffer *staticArrayBuffer);
82 EtsObject *CreateDynamicTypedArray(EtsEscompatArrayBuffer *staticArrayBuffer, int32_t typedArrayType, double length,
83                                    double byteOffset);
84 EtsObject *CreateDynamicDataView(EtsEscompatArrayBuffer *staticArrayBuffer, double byteLength, double byteOffset);
85 void SetInteropRuntimeLinker(EtsRuntimeLinker *linker);
86 
87 template <typename T>
JSValueNamedGetter(JSValue * etsJsValue,EtsString * etsPropName)88 typename T::cpptype JSValueNamedGetter(JSValue *etsJsValue, EtsString *etsPropName)
89 {
90     auto coro = EtsCoroutine::GetCurrent();
91     auto ctx = InteropCtx::Current(coro);
92     if (ctx == nullptr) {
93         ThrowNoInteropContextException();
94         return {};
95     }
96     INTEROP_CODE_SCOPE_ETS(coro);
97     auto env = ctx->GetJSEnv();
98     NapiScope jsHandleScope(env);
99 
100     PandaString propName = etsPropName->GetMutf8();
101     auto res = JSValueGetByName<T>(ctx, etsJsValue, propName.c_str());
102     if (UNLIKELY(!res)) {
103         ctx->ForwardJSException(coro);
104         return {};
105     }
106     return res.value();
107 }
108 
109 template <typename T>
JSValueNamedSetter(JSValue * etsJsValue,EtsString * etsPropName,typename T::cpptype etsPropVal)110 void JSValueNamedSetter(JSValue *etsJsValue, EtsString *etsPropName, typename T::cpptype etsPropVal)
111 {
112     auto coro = EtsCoroutine::GetCurrent();
113     auto ctx = InteropCtx::Current(coro);
114     if (ctx == nullptr) {
115         ThrowNoInteropContextException();
116         return;
117     }
118     INTEROP_CODE_SCOPE_ETS(coro);
119     auto env = ctx->GetJSEnv();
120     NapiScope jsHandleScope(env);
121 
122     PandaString propName = etsPropName->GetMutf8();
123     JSValueSetByName<T>(ctx, etsJsValue, propName.c_str(), etsPropVal);
124 }
125 
126 template <typename T>
JSValueIndexedGetter(JSValue * etsJsValue,int32_t index)127 typename T::cpptype JSValueIndexedGetter(JSValue *etsJsValue, int32_t index)
128 {
129     auto coro = EtsCoroutine::GetCurrent();
130     auto ctx = InteropCtx::Current(coro);
131     if (ctx == nullptr) {
132         ThrowNoInteropContextException();
133         return {};
134     }
135     INTEROP_CODE_SCOPE_ETS(coro);
136     auto env = ctx->GetJSEnv();
137     NapiScope jsHandleScope(env);
138 
139     napi_value result;
140     napi_value jsVal = etsJsValue->GetNapiValue(env);
141     napi_status jsStatus;
142     {
143         ScopedNativeCodeThread nativeScope(coro);
144         jsStatus = napi_get_element(env, jsVal, index, &result);
145     }
146 
147     if (jsStatus != napi_ok) {
148         ctx->ForwardJSException(coro);
149         return {};
150     }
151 
152     auto res = T::UnwrapWithNullCheck(ctx, env, result);
153     if (!res) {
154         ctx->ForwardJSException(coro);
155         return {};
156     }
157 
158     return res.value();
159 }
160 
161 template <typename T>
JSValueIndexedSetter(JSValue * etsJsValue,int32_t index,typename T::cpptype value)162 void JSValueIndexedSetter(JSValue *etsJsValue, int32_t index, typename T::cpptype value)
163 {
164     auto coro = EtsCoroutine::GetCurrent();
165     auto ctx = InteropCtx::Current(coro);
166     INTEROP_CODE_SCOPE_ETS(coro);
167     auto env = ctx->GetJSEnv();
168     NapiScope jsHandleScope(env);
169     napi_status jsStatus;
170     {
171         ScopedNativeCodeThread nativeScope(coro);
172 
173         jsStatus = napi_set_element(env, JSConvertJSValue::WrapWithNullCheck(env, etsJsValue), index,
174                                     T::WrapWithNullCheck(env, value));
175     }
176     if (jsStatus != napi_ok) {
177         ctx->ForwardJSException(coro);
178     }
179 }
180 
181 template <typename T>
ConvertToLocal(typename T::cpptype etsValue)182 void *ConvertToLocal(typename T::cpptype etsValue)
183 {
184     auto coro = EtsCoroutine::GetCurrent();
185     auto ctx = InteropCtx::Current(coro);
186     if (ctx == nullptr) {
187         ThrowNoInteropContextException();
188         return nullptr;
189     }
190     INTEROP_CODE_SCOPE_ETS(coro);
191     napi_env env = ctx->GetJSEnv();
192     napi_value localJsValue = T::Wrap(env, etsValue);
193     if (UNLIKELY(localJsValue == nullptr)) {
194         ctx->ForwardJSException(coro);
195         return nullptr;
196     }
197     return localJsValue;
198 }
199 
200 template <bool USE_RET>
CompilerJSCallFunction(void * obj,void * fn,uint32_t argc,void * args)201 std::conditional_t<USE_RET, void *, void> CompilerJSCallFunction(void *obj, void *fn, uint32_t argc, void *args)
202 {
203     auto jsThis = ToLocal(obj);
204     auto jsFn = ToLocal(fn);
205     auto jsArgs = reinterpret_cast<napi_value *>(args);
206     auto coro = EtsCoroutine::GetCurrent();
207 
208     InteropCtx *ctx = nullptr;
209     if constexpr (USE_RET) {
210         ctx = InteropCtx::Current(coro);
211         if (ctx == nullptr) {
212             ThrowNoInteropContextException();
213             return nullptr;
214         }
215     } else {
216         ctx = InteropCtx::Current(coro);
217         if (ctx == nullptr) {
218             ThrowNoInteropContextException();
219             return;
220         }
221     }
222     ASSERT(ctx != nullptr);
223 
224     INTEROP_CODE_SCOPE_ETS(coro);
225     napi_env env = ctx->GetJSEnv();
226 
227     [[maybe_unused]] napi_value jsRet;
228     napi_status jsStatus;
229     {
230         ScopedNativeCodeThread nativeScope(coro);
231         if constexpr (USE_RET) {
232             jsStatus = napi_call_function(env, jsThis, jsFn, argc, jsArgs, &jsRet);
233         } else {
234             jsStatus = napi_call_function(env, jsThis, jsFn, argc, jsArgs, nullptr);
235         }
236     }
237 
238     if (UNLIKELY(jsStatus != napi_ok)) {
239         INTEROP_FATAL_IF(jsStatus != napi_pending_exception);
240         ctx->ForwardJSException(coro);
241         INTEROP_LOG(DEBUG) << "JSValueJSCall: exit with pending exception";
242         if constexpr (USE_RET) {
243             return nullptr;
244         }
245     }
246     if constexpr (USE_RET) {
247         return jsRet;
248     }
249 }
250 
HandleExceptions(napi_env env,InteropCtx * ctx)251 inline void HandleExceptions(napi_env env, InteropCtx *ctx)
252 {
253     if (NapiIsExceptionPending(env)) {
254         ctx->ForwardJSException(EtsCoroutine::GetCurrent());
255     }
256     ASSERT(ctx->SanityETSExceptionPending());
257 }
258 
259 template <typename CONVERTOR>
ConvertFromLocal(void * value)260 typename CONVERTOR::cpptype ConvertFromLocal(void *value)
261 {
262     auto coro = EtsCoroutine::GetCurrent();
263     auto ctx = InteropCtx::Current(coro);
264     if (ctx == nullptr) {
265         ThrowNoInteropContextException();
266         if constexpr (!std::is_pointer_v<typename CONVERTOR::cpptype>) {
267             return 0;
268         } else {
269             return nullptr;
270         }
271     }
272     INTEROP_CODE_SCOPE_ETS(coro);
273     napi_env env = ctx->GetJSEnv();
274     auto res = CONVERTOR::Unwrap(ctx, env, ToLocal(value));
275     if (UNLIKELY(!res.has_value())) {
276         HandleExceptions(env, ctx);
277         if constexpr (!std::is_pointer_v<typename CONVERTOR::cpptype>) {
278             return 0;
279         } else {
280             return nullptr;
281         }
282     }
283     return res.value();
284 }
285 
286 template <>
287 // CC-OFFNXT(G.FUD.06) solid logic
288 inline JSValue *ConvertFromLocal<JSConvertJSValue>(void *value)
289 {
290     INTEROP_CODE_SCOPE_ETS(EtsCoroutine::GetCurrent());
291 
292     auto ctx = InteropCtx::Current(EtsCoroutine::GetCurrent());
293     if (ctx == nullptr) {
294         ThrowNoInteropContextException();
295         return nullptr;
296     }
297     if (IsUndefined(ctx->GetJSEnv(), ToLocal(value))) {
298         return nullptr;
299     }
300     if (auto res = JSConvertJSValue::Unwrap(ctx, ctx->GetJSEnv(), ToLocal(value)); res.has_value()) {
301         return res.value();
302     }
303     HandleExceptions(ctx->GetJSEnv(), ctx);
304     return nullptr;
305 }
306 
307 }  // namespace ark::ets::interop::js
308 
309 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_
310