• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-2024 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 
25 namespace ark::ets::interop::js {
26 
27 void JSRuntimeFinalizationRegistryCallback(EtsObject *cbarg);
28 JSValue *JSRuntimeNewJSValueDouble(double v);
29 JSValue *JSRuntimeNewJSValueBoolean(uint8_t v);
30 JSValue *JSRuntimeNewJSValueString(EtsString *v);
31 JSValue *JSRuntimeNewJSValueObject(EtsObject *v);
32 double JSRuntimeGetValueDouble(JSValue *etsJsValue);
33 uint8_t JSRuntimeGetValueBoolean(JSValue *etsJsValue);
34 EtsString *JSRuntimeGetValueString(JSValue *etsJsValue);
35 EtsObject *JSRuntimeGetValueObject(JSValue *etsJsValue, EtsClass *clsObj);
36 JSValue *JSRuntimeGetUndefined();
37 JSValue *JSRuntimeGetNull();
38 JSValue *JSRuntimeGetGlobal();
39 JSValue *JSRuntimeCreateObject();
40 uint8_t JSRuntimeInstanceOf(JSValue *object, JSValue *ctor);
41 uint8_t JSRuntimeInstanceOfDynamic(JSValue *object, JSValue *ctor);
42 uint8_t JSRuntimeInstanceOfStatic(JSValue *etsJsValue, EtsClass *etsCls);
43 std::pair<std::string_view, std::string_view> ResolveModuleName(std::string_view module);
44 JSValue *JSRuntimeLoadModule(EtsString *module);
45 uint8_t JSRuntimeStrictEqual([[maybe_unused]] JSValue *lhs, [[maybe_unused]] JSValue *rhs);
46 EtsString *JSValueToString(JSValue *object);
47 napi_value ToLocal(void *value);
48 void *CompilerGetJSNamedProperty(void *val, char *propStr);
49 void *CompilerGetJSProperty(void *val, void *prop);
50 void *CompilerGetJSElement(void *val, int32_t index);
51 void *CompilerJSCallCheck(void *fn);
52 void *CompilerJSNewInstance(void *fn, uint32_t argc, void *args);
53 void CreateLocalScope();
54 void CompilerDestroyLocalScope();
55 void *CompilerLoadJSConstantPool();
56 void CompilerInitJSCallClassForCtx(void *klassPtr);
57 void *CompilerConvertVoidToLocal();
58 void *CompilerConvertRefTypeToLocal(EtsObject *etsValue);
59 void PromiseInteropResolve(EtsObject *etsValue, EtsLong deferred);
60 void PromiseInteropReject(EtsObject *etsValue, EtsLong deferred);
61 EtsString *JSONStringify(JSValue *jsvalue);
62 EtsString *CompilerConvertLocalToString(void *value);
63 EtsObject *CompilerConvertLocalToRefType(void *klassPtr, void *value);
64 
65 template <typename T>
JSValueNamedGetter(JSValue * etsJsValue,EtsString * etsPropName)66 typename T::cpptype JSValueNamedGetter(JSValue *etsJsValue, EtsString *etsPropName)
67 {
68     auto coro = EtsCoroutine::GetCurrent();
69     auto ctx = InteropCtx::Current(coro);
70     INTEROP_CODE_SCOPE_ETS(coro);
71     auto env = ctx->GetJSEnv();
72     NapiScope jsHandleScope(env);
73 
74     PandaString propName = etsPropName->GetMutf8();
75     auto res = JSValueGetByName<T>(ctx, etsJsValue, propName.c_str());
76     if (UNLIKELY(!res)) {
77         ctx->ForwardJSException(coro);
78         return {};
79     }
80     return res.value();
81 }
82 
83 template <typename T>
JSValueNamedSetter(JSValue * etsJsValue,EtsString * etsPropName,typename T::cpptype etsPropVal)84 void JSValueNamedSetter(JSValue *etsJsValue, EtsString *etsPropName, typename T::cpptype etsPropVal)
85 {
86     auto coro = EtsCoroutine::GetCurrent();
87     auto ctx = InteropCtx::Current(coro);
88     INTEROP_CODE_SCOPE_ETS(coro);
89     auto env = ctx->GetJSEnv();
90     NapiScope jsHandleScope(env);
91 
92     PandaString propName = etsPropName->GetMutf8();
93     bool res = JSValueSetByName<T>(ctx, etsJsValue, propName.c_str(), etsPropVal);
94     if (UNLIKELY(!res)) {
95         ctx->ForwardJSException(coro);
96     }
97 }
98 
99 template <typename T>
JSValueIndexedGetter(JSValue * etsJsValue,int32_t index)100 typename T::cpptype JSValueIndexedGetter(JSValue *etsJsValue, int32_t index)
101 {
102     auto coro = EtsCoroutine::GetCurrent();
103     auto ctx = InteropCtx::Current(coro);
104     INTEROP_CODE_SCOPE_ETS(coro);
105     auto env = ctx->GetJSEnv();
106     NapiScope jsHandleScope(env);
107 
108     napi_value result;
109     napi_value jsVal = etsJsValue->GetNapiValue(env);
110     auto rc = napi_get_element(env, jsVal, index, &result);
111     if (UNLIKELY(NapiThrownGeneric(rc))) {
112         ctx->ForwardJSException(coro);
113         return {};
114     }
115 
116     auto res = T::UnwrapWithNullCheck(ctx, env, result);
117     if (!res) {
118         ctx->ForwardJSException(coro);
119         return {};
120     }
121 
122     return res.value();
123 }
124 
125 template <typename T>
ConvertToLocal(typename T::cpptype etsValue)126 void *ConvertToLocal(typename T::cpptype etsValue)
127 {
128     auto coro = EtsCoroutine::GetCurrent();
129     auto ctx = InteropCtx::Current(coro);
130     INTEROP_CODE_SCOPE_ETS(coro);
131     napi_env env = ctx->GetJSEnv();
132     napi_value localJsValue = T::Wrap(env, etsValue);
133     if (UNLIKELY(localJsValue == nullptr)) {
134         ctx->ForwardJSException(coro);
135         return nullptr;
136     }
137     return localJsValue;
138 }
139 
140 template <bool USE_RET>
CompilerJSCallFunction(void * obj,void * fn,uint32_t argc,void * args)141 std::conditional_t<USE_RET, void *, void> CompilerJSCallFunction(void *obj, void *fn, uint32_t argc, void *args)
142 {
143     auto jsThis = ToLocal(obj);
144     auto jsFn = ToLocal(fn);
145     auto jsArgs = reinterpret_cast<napi_value *>(args);
146     auto coro = EtsCoroutine::GetCurrent();
147     auto ctx = InteropCtx::Current(coro);
148     INTEROP_CODE_SCOPE_ETS(coro);
149     napi_env env = ctx->GetJSEnv();
150 
151     [[maybe_unused]] napi_value jsRet;
152     napi_status jsStatus;
153     {
154         ScopedNativeCodeThread nativeScope(coro);
155         if constexpr (USE_RET) {
156             jsStatus = napi_call_function(env, jsThis, jsFn, argc, jsArgs, &jsRet);
157         } else {
158             jsStatus = napi_call_function(env, jsThis, jsFn, argc, jsArgs, nullptr);
159         }
160     }
161 
162     if (UNLIKELY(jsStatus != napi_ok)) {
163         INTEROP_FATAL_IF(jsStatus != napi_pending_exception);
164         ctx->ForwardJSException(coro);
165         INTEROP_LOG(DEBUG) << "JSValueJSCall: exit with pending exception";
166         if constexpr (USE_RET) {
167             return nullptr;
168         }
169     }
170     if constexpr (USE_RET) {
171         return jsRet;
172     }
173 }
174 
HandleExceptions(napi_env env,InteropCtx * ctx)175 inline void HandleExceptions(napi_env env, InteropCtx *ctx)
176 {
177     auto coro = EtsCoroutine::GetCurrent();
178 
179     if (NapiIsExceptionPending(env)) {
180         ctx->ForwardJSException(coro);
181     }
182     ASSERT(ctx->SanityETSExceptionPending());
183 }
184 
185 template <typename CONVERTOR>
ConvertFromLocal(void * value)186 typename CONVERTOR::cpptype ConvertFromLocal(void *value)
187 {
188     auto coro = EtsCoroutine::GetCurrent();
189     auto ctx = InteropCtx::Current(coro);
190     INTEROP_CODE_SCOPE_ETS(coro);
191     napi_env env = ctx->GetJSEnv();
192     auto res = CONVERTOR::Unwrap(ctx, env, ToLocal(value));
193     if (UNLIKELY(!res.has_value())) {
194         HandleExceptions(env, ctx);
195         if constexpr (!std::is_pointer_v<typename CONVERTOR::cpptype>) {
196             return 0;
197         } else {
198             return nullptr;
199         }
200     }
201     return res.value();
202 }
203 
204 template <>
205 inline JSValue *ConvertFromLocal<JSConvertJSValue>(void *value)
206 {
207     INTEROP_CODE_SCOPE_ETS(EtsCoroutine::GetCurrent());
208 
209     auto ctx = InteropCtx::Current(EtsCoroutine::GetCurrent());
210     if (!IsNull(ctx->GetJSEnv(), ToLocal(value))) {
211         auto res = JSConvertJSValue::Unwrap(ctx, ctx->GetJSEnv(), ToLocal(value));
212         if (res.has_value()) {
213             return res.value();
214         }
215 
216         HandleExceptions(ctx->GetJSEnv(), ctx);
217     }
218 
219     return nullptr;
220 }
221 
222 }  // namespace ark::ets::interop::js
223 
224 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTRINSICS_API_IMPL_H_
225