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