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
16 #include <cstddef>
17 #include <string>
18 #include <variant>
19 #include <vector>
20 #include <map>
21 #include <securec.h>
22
23 // NOLINTBEGIN
24
25 #ifdef TS_INTEROP_MODULE
26 #undef TS_INTEROP_MODULE
27 #endif
28
29 #define TS_INTEROP_MODULE InteropNativeModule
30 #include "interop-logging.h"
31 #include "convertors-napi.h"
32 #include "common-interop.h"
33
34 #if TS_INTEROP_PROFILER
35 #include "profiler.h"
36
37 InteropProfiler *InteropProfiler::_instance = nullptr;
38
39 #endif
40
41 using std::string;
42
43 // Callback dispatcher MOVED to convertors-napi.cc.
44 // Let's keep platform-specific parts of the code together
45
46 typedef void (*HoldT)(KInt);
47
impl_getTypeOfVariant(KNativePointer varPtr)48 KInt impl_getTypeOfVariant(KNativePointer varPtr)
49 {
50 auto *var = reinterpret_cast<std::variant<int, std::string> *>(varPtr);
51 if (std::get_if<int>(var) != nullptr) {
52 return 0;
53 } else {
54 return 1;
55 }
56 }
TS_INTEROP_1(getTypeOfVariant,KInt,KNativePointer)57 TS_INTEROP_1(getTypeOfVariant, KInt, KNativePointer)
58
59 KNativePointer impl_getStringFromVariant(KNativePointer varPtr)
60 {
61 auto *var = reinterpret_cast<std::variant<int, std::string> *>(varPtr);
62 auto *res = new std::string(*std::get_if<std::string>(var));
63 return res;
64 }
TS_INTEROP_1(getStringFromVariant,KNativePointer,KNativePointer)65 TS_INTEROP_1(getStringFromVariant, KNativePointer, KNativePointer)
66
67 KInt impl_getIntFromVariant(KNativePointer varPtr)
68 {
69 auto *var = reinterpret_cast<std::variant<int, std::string> *>(varPtr);
70 auto res = *std::get_if<int>(var);
71 return res;
72 }
TS_INTEROP_1(getIntFromVariant,KInt,KNativePointer)73 TS_INTEROP_1(getIntFromVariant, KInt, KNativePointer)
74
75 KInteropBuffer impl_MaterializeBuffer(KNativePointer data, KLong length, KInt resourceId, KNativePointer holdPtr,
76 KNativePointer releasePtr)
77 {
78 auto hold = reinterpret_cast<void (*)(KInt)>(holdPtr);
79 auto release = reinterpret_cast<void (*)(KInt)>(releasePtr);
80 hold(resourceId);
81 return KInteropBuffer {length, data, resourceId, release};
82 }
TS_INTEROP_5(MaterializeBuffer,KInteropBuffer,KNativePointer,KLong,KInt,KNativePointer,KNativePointer)83 TS_INTEROP_5(MaterializeBuffer, KInteropBuffer, KNativePointer, KLong, KInt, KNativePointer, KNativePointer)
84
85 KNativePointer impl_GetNativeBufferPointer(KInteropBuffer buffer)
86 {
87 return buffer.data;
88 }
TS_INTEROP_1(GetNativeBufferPointer,KNativePointer,KInteropBuffer)89 TS_INTEROP_1(GetNativeBufferPointer, KNativePointer, KInteropBuffer)
90
91 KInt impl_StringLength(KNativePointer ptr)
92 {
93 auto *s = reinterpret_cast<string *>(ptr);
94 return s->length();
95 }
TS_INTEROP_1(StringLength,KInt,KNativePointer)96 TS_INTEROP_1(StringLength, KInt, KNativePointer)
97
98 void impl_StringData(KNativePointer ptr, KByte *bytes, KUInt size)
99 {
100 auto *s = reinterpret_cast<string *>(ptr);
101 if (s != nullptr) {
102 memcpy_s(bytes, size, s->c_str(), size);
103 }
104 }
TS_INTEROP_V3(StringData,KNativePointer,KByte *,KUInt)105 TS_INTEROP_V3(StringData, KNativePointer, KByte *, KUInt)
106
107 KNativePointer impl_StringMake(const KStringPtr &str)
108 {
109 return new string(str.c_str());
110 }
TS_INTEROP_1(StringMake,KNativePointer,KStringPtr)111 TS_INTEROP_1(StringMake, KNativePointer, KStringPtr)
112
113 // For slow runtimes w/o fast encoders.
114 KInt impl_ManagedStringWrite(const KStringPtr &str, KByte *buffer, KInt offset)
115 {
116 memcpy_s(buffer + offset, str.length() + 1, str.c_str(), str.length() + 1);
117 return str.length() + 1;
118 }
TS_INTEROP_3(ManagedStringWrite,KInt,KStringPtr,KByte *,KInt)119 TS_INTEROP_3(ManagedStringWrite, KInt, KStringPtr, KByte *, KInt)
120
121 void stringFinalizer(string *ptr)
122 {
123 delete ptr;
124 }
impl_GetStringFinalizer()125 KNativePointer impl_GetStringFinalizer()
126 {
127 return fnPtr<string>(stringFinalizer);
128 }
TS_INTEROP_0(GetStringFinalizer,KNativePointer)129 TS_INTEROP_0(GetStringFinalizer, KNativePointer)
130
131 void impl_InvokeFinalizer(KNativePointer obj, KNativePointer finalizer)
132 {
133 auto finalizerF = reinterpret_cast<void (*)(KNativePointer)>(finalizer);
134 finalizerF(obj);
135 }
TS_INTEROP_V2(InvokeFinalizer,KNativePointer,KNativePointer)136 TS_INTEROP_V2(InvokeFinalizer, KNativePointer, KNativePointer)
137
138 KInt impl_GetPtrVectorSize(KNativePointer ptr)
139 {
140 auto *vec = reinterpret_cast<std::vector<void *> *>(ptr);
141 return vec->size();
142 }
TS_INTEROP_1(GetPtrVectorSize,KInt,KNativePointer)143 TS_INTEROP_1(GetPtrVectorSize, KInt, KNativePointer)
144
145 KNativePointer impl_GetPtrVectorElement(KNativePointer ptr, KInt index)
146 {
147 auto vector = reinterpret_cast<std::vector<void *> *>(ptr);
148 auto element = vector->at(index);
149 return element;
150 }
TS_INTEROP_2(GetPtrVectorElement,KNativePointer,KNativePointer,KInt)151 TS_INTEROP_2(GetPtrVectorElement, KNativePointer, KNativePointer, KInt)
152
153 inline KUInt UnpackUInt(const KByte *bytes)
154 {
155 return (bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24));
156 }
157
MakeStringVector(KStringArray strArray)158 std::vector<KStringPtr> MakeStringVector(KStringArray strArray)
159 {
160 if (strArray == nullptr) {
161 return std::vector<KStringPtr>(0);
162 }
163 KUInt arraySize = UnpackUInt(strArray);
164 std::vector<KStringPtr> res(arraySize);
165 size_t offset = sizeof(KUInt);
166 for (KUInt i = 0; i < arraySize; ++i) {
167 int len = UnpackUInt(strArray + offset);
168 res[i].assign((const char *)(strArray + offset + sizeof(KUInt)), len);
169 offset += len + sizeof(KUInt);
170 }
171 return res;
172 }
173
MakeStringVector(KNativePointerArray arr,KInt length)174 std::vector<KStringPtr> MakeStringVector(KNativePointerArray arr, KInt length)
175 {
176 if (arr == nullptr) {
177 return std::vector<KStringPtr>(0);
178 } else {
179 std::vector<KStringPtr> res(length);
180 char **strings = reinterpret_cast<char **>(arr);
181 for (KInt i = 0; i < length; ++i) {
182 const char *str = reinterpret_cast<const char *>(strings[i]);
183 res[i].assign(str);
184 }
185 return res;
186 }
187 }
188
189 typedef KInt (*LoadVirtualMachine_t)(KInt vmKind, const char *classPath, const char *libraryPath,
190 void *currentVMContext);
191 typedef KNativePointer (*StartApplication_t)(const char *appUrl, const char *appParams);
192 typedef KBoolean (*RunApplication_t)(const KInt arg0, const KInt arg1);
193 typedef void (*EmitEventT)(const KInt type, const KInt target, const KInt arg0, const KInt arg1);
194
195 static CallbackCallert g_callbackCaller = nullptr;
setCallbackCaller(CallbackCallert callbackCaller)196 void setCallbackCaller(CallbackCallert callbackCaller)
197 {
198 g_callbackCaller = callbackCaller;
199 }
200
impl_CallCallback(KInt callbackKind,KByte * args,KInt argsSize)201 void impl_CallCallback(KInt callbackKind, KByte *args, KInt argsSize)
202 {
203 if (g_callbackCaller != nullptr) {
204 g_callbackCaller(callbackKind, args, argsSize);
205 }
206 }
207 TS_INTEROP_V3(CallCallback, KInt, KByte *, KInt)
208
209 static CallbackCallerSynct g_callbackCallerSync = nullptr;
setCallbackCallerSync(CallbackCallerSynct callbackCallerSync)210 void setCallbackCallerSync(CallbackCallerSynct callbackCallerSync)
211 {
212 g_callbackCallerSync = callbackCallerSync;
213 }
214
impl_CallCallbackSync(KVMContext vmContext,KInt callbackKind,KByte * args,KInt argsSize)215 void impl_CallCallbackSync(KVMContext vmContext, KInt callbackKind, KByte *args, KInt argsSize)
216 {
217 if (g_callbackCallerSync) {
218 g_callbackCallerSync(vmContext, callbackKind, args, argsSize);
219 }
220 }
TS_INTEROP_CTX_V3(CallCallbackSync,KInt,KByte *,KInt)221 TS_INTEROP_CTX_V3(CallCallbackSync, KInt, KByte *, KInt)
222
223 void impl_CallCallbackResourceHolder(KNativePointer holder, KInt resourceId)
224 {
225 reinterpret_cast<void (*)(KInt)>(holder)(resourceId);
226 }
TS_INTEROP_V2(CallCallbackResourceHolder,KNativePointer,KInt)227 TS_INTEROP_V2(CallCallbackResourceHolder, KNativePointer, KInt)
228
229 void impl_CallCallbackResourceReleaser(KNativePointer releaser, KInt resourceId)
230 {
231 reinterpret_cast<void (*)(KInt)>(releaser)(resourceId);
232 }
TS_INTEROP_V2(CallCallbackResourceReleaser,KNativePointer,KInt)233 TS_INTEROP_V2(CallCallbackResourceReleaser, KNativePointer, KInt)
234
235 // CC-OFFNXT(G.EXP.01) false positive
236 #define __QUOTE(x) #x
237 #define QUOTE(x) __QUOTE(x)
238
239 #ifndef INTEROP_LIBRARY_NAME
240 #error "INTEROP_LIBRARY_NAME must be defined"
241 #endif
242
243 void impl_NativeLog(const KStringPtr &str)
244 {
245 fprintf(stdout, "%s: %s\n", QUOTE(INTEROP_LIBRARY_NAME), str.c_str());
246 fflush(stdout);
247 }
TS_INTEROP_V1(NativeLog,KStringPtr)248 TS_INTEROP_V1(NativeLog, KStringPtr)
249
250 int32_t callCallback(KVMContext context, int32_t methodId, uint8_t *argsData, int32_t argsLength)
251 {
252 TS_INTEROP_CALL_INT(context, methodId, argsLength, argsData);
253 return 0;
254 }
255
resolveDeferred(KVMDeferred * deferred,uint8_t * argsData,int32_t argsLength)256 void resolveDeferred(KVMDeferred *deferred, [[maybe_unused]] uint8_t *argsData, [[maybe_unused]] int32_t argsLength)
257 {
258 napi_acquire_threadsafe_function((napi_threadsafe_function)deferred->handler);
259 auto status =
260 napi_call_threadsafe_function((napi_threadsafe_function)deferred->handler, deferred, napi_tsfn_nonblocking);
261 if (status != napi_ok)
262 LOGE("cannot call thread-safe function; status=%d", status);
263 napi_release_threadsafe_function((napi_threadsafe_function)deferred->handler, napi_tsfn_release);
264 }
265
rejectDeferred(KVMDeferred * deferred,const char * message)266 void rejectDeferred(KVMDeferred *deferred, [[maybe_unused]] const char *message)
267 {
268 napi_release_threadsafe_function((napi_threadsafe_function)deferred->handler, napi_tsfn_release);
269 delete deferred;
270 }
271
resolveDeferredImpl(napi_env env,napi_value js_callback,KVMDeferred * deferred,void * data)272 void resolveDeferredImpl(napi_env env, [[maybe_unused]] napi_value js_callback, KVMDeferred *deferred,
273 [[maybe_unused]] void *data)
274 {
275 napi_value undefined = nullptr;
276 napi_get_undefined(env, &undefined);
277 auto status = napi_resolve_deferred(env, (napi_deferred)deferred->context, undefined);
278 if (status != napi_ok)
279 LOGE("cannot resolve deferred; status=%d", status);
280 delete deferred;
281 }
282
releaseDeferred(KVMDeferred * deferred)283 [[maybe_unused]] static void releaseDeferred(KVMDeferred *deferred)
284 {
285 delete deferred;
286 }
287
CreateDeferred(KVMContext vmContext,KVMObjectHandle * promiseHandle)288 KVMDeferred *CreateDeferred(KVMContext vmContext, KVMObjectHandle *promiseHandle)
289 {
290 KVMDeferred *deferred = new KVMDeferred();
291 deferred->resolve = resolveDeferred;
292 deferred->reject = rejectDeferred;
293 // NOTE(khil): mb move\remove to interop!
294 napi_env env = (napi_env)vmContext;
295 napi_value promise;
296 napi_value resourceName;
297 size_t napiStrLen = 5;
298 napi_create_string_utf8(env, "Async", napiStrLen, &resourceName);
299 auto status = napi_create_promise(env, (napi_deferred *)&deferred->context, &promise);
300 if (status != napi_ok)
301 LOGE("cannot make a promise; status=%d", status);
302 status = napi_create_threadsafe_function(env, nullptr, nullptr, resourceName, 0, 1, nullptr, nullptr, deferred,
303 (napi_threadsafe_function_call_js)resolveDeferredImpl,
304 (napi_threadsafe_function *)&deferred->handler);
305 if (status != napi_ok)
306 LOGE("cannot make threadsafe function; status=%d", status);
307 *promiseHandle = (KVMObjectHandle)promise;
308 return deferred;
309 }
310
311 // Allocate, so CTX versions.
impl_Utf8ToString(KVMContext vmContext,KByte * data,KInt offset,KInt length)312 KStringPtr impl_Utf8ToString([[maybe_unused]] KVMContext vmContext, KByte *data, KInt offset, KInt length)
313 {
314 KStringPtr result((const char *)(data + offset), length, false);
315 return result;
316 }
TS_INTEROP_CTX_3(Utf8ToString,KStringPtr,KByte *,KInt,KInt)317 TS_INTEROP_CTX_3(Utf8ToString, KStringPtr, KByte *, KInt, KInt)
318
319 KStringPtr impl_StdStringToString([[maybe_unused]] KVMContext vmContext, KNativePointer stringPtr)
320 {
321 auto *str = reinterpret_cast<std::string *>(stringPtr);
322 KStringPtr result(str->c_str(), str->size(), false);
323 return result;
324 }
TS_INTEROP_CTX_1(StdStringToString,KStringPtr,KNativePointer)325 TS_INTEROP_CTX_1(StdStringToString, KStringPtr, KNativePointer)
326
327 KInteropReturnBuffer impl_RawReturnData([[maybe_unused]] KVMContext vmContext, KInt v1, KInt v2)
328 {
329 void *data = new int8_t[v1];
330 memset_s(data, v2, v1, v2);
331 KInteropReturnBuffer buffer = {v1, data, [](KNativePointer ptr, KInt) { delete[](int8_t *) ptr; }};
332 return buffer;
333 }
334 TS_INTEROP_CTX_2(RawReturnData, KInteropReturnBuffer, KInt, KInt)
335
336 // NOLINTEND
337