11#include " CFunction.h"
2+ #include < dispatch/dispatch.h>
3+ #include < cstring>
4+ #include < vector>
5+ #include " Block.h"
26#include " ClassMember.h"
7+ #include " Interop.h"
38#include " ObjCBridge.h"
49#include " SignatureDispatch.h"
510#include " ffi/NativeScriptException.h"
611#include " ffi/Tasks.h"
7- #include < cstring>
8- #include < vector>
912#ifdef ENABLE_JS_RUNTIME
1013#include " jsr.h"
1114#endif
1215
1316namespace nativescript {
1417
18+ namespace {
19+
20+ inline bool unwrapCompatNativeHandleForCFunction (napi_env env, napi_value value, void ** out) {
21+ if (value == nullptr || out == nullptr ) {
22+ return false ;
23+ }
24+
25+ if (Pointer::isInstance (env, value)) {
26+ Pointer* ptr = Pointer::unwrap (env, value);
27+ *out = ptr != nullptr ? ptr->data : nullptr ;
28+ return ptr != nullptr ;
29+ }
30+
31+ if (Reference::isInstance (env, value)) {
32+ Reference* ref = Reference::unwrap (env, value);
33+ *out = ref != nullptr ? ref->data : nullptr ;
34+ return ref != nullptr ;
35+ }
36+
37+ napi_valuetype valueType = napi_undefined;
38+ if (napi_typeof (env, value, &valueType) != napi_ok) {
39+ return false ;
40+ }
41+
42+ if (valueType == napi_bigint) {
43+ uint64_t raw = 0 ;
44+ bool lossless = false ;
45+ if (napi_get_value_bigint_uint64 (env, value, &raw, &lossless) != napi_ok) {
46+ return false ;
47+ }
48+ *out = reinterpret_cast <void *>(static_cast <uintptr_t >(raw));
49+ return true ;
50+ }
51+
52+ if (valueType == napi_external) {
53+ return napi_get_value_external (env, value, out) == napi_ok;
54+ }
55+
56+ if (valueType != napi_object && valueType != napi_function) {
57+ return false ;
58+ }
59+
60+ bool hasNativePointer = false ;
61+ if (napi_has_named_property (env, value, " __ns_native_ptr" , &hasNativePointer) == napi_ok &&
62+ hasNativePointer) {
63+ napi_value nativePointerValue = nullptr ;
64+ if (napi_get_named_property (env, value, " __ns_native_ptr" , &nativePointerValue) == napi_ok &&
65+ napi_get_value_external (env, nativePointerValue, out) == napi_ok && *out != nullptr ) {
66+ return true ;
67+ }
68+ }
69+
70+ return napi_unwrap (env, value, out) == napi_ok && *out != nullptr ;
71+ }
72+
73+ inline napi_value createCompatDispatchQueueWrapperForCFunction (napi_env env,
74+ dispatch_queue_t queue) {
75+ if (queue == nullptr ) {
76+ napi_value nullValue = nullptr ;
77+ napi_get_null (env, &nullValue);
78+ return nullValue;
79+ }
80+
81+ return Pointer::create (env, reinterpret_cast <void *>(queue));
82+ }
83+
84+ inline napi_value tryCallCompatLibdispatchFunction (napi_env env, napi_callback_info cbinfo,
85+ const char * functionName) {
86+ if (strcmp (functionName, " dispatch_get_global_queue" ) == 0 ) {
87+ size_t argc = 2 ;
88+ napi_value argv[2 ] = {nullptr , nullptr };
89+ napi_get_cb_info (env, cbinfo, &argc, argv, nullptr , nullptr );
90+
91+ int64_t identifier = 0 ;
92+ if (argc > 0 ) {
93+ napi_valuetype identifierType = napi_undefined;
94+ if (napi_typeof (env, argv[0 ], &identifierType) == napi_ok && identifierType == napi_bigint) {
95+ bool lossless = false ;
96+ if (napi_get_value_bigint_int64 (env, argv[0 ], &identifier, &lossless) != napi_ok) {
97+ napi_throw_type_error (env, nullptr ,
98+ " dispatch_get_global_queue expects a numeric identifier." );
99+ return nullptr ;
100+ }
101+ } else {
102+ napi_value coercedIdentifier = nullptr ;
103+ if (napi_coerce_to_number (env, argv[0 ], &coercedIdentifier) != napi_ok ||
104+ napi_get_value_int64 (env, coercedIdentifier, &identifier) != napi_ok) {
105+ napi_throw_type_error (env, nullptr ,
106+ " dispatch_get_global_queue expects a numeric identifier." );
107+ return nullptr ;
108+ }
109+ }
110+ }
111+
112+ uint64_t flags = 0 ;
113+ if (argc > 1 ) {
114+ napi_valuetype flagsType = napi_undefined;
115+ if (napi_typeof (env, argv[1 ], &flagsType) == napi_ok && flagsType == napi_bigint) {
116+ bool lossless = false ;
117+ if (napi_get_value_bigint_uint64 (env, argv[1 ], &flags, &lossless) != napi_ok) {
118+ napi_throw_type_error (env, nullptr , " dispatch_get_global_queue expects numeric flags." );
119+ return nullptr ;
120+ }
121+ } else {
122+ napi_value coercedFlags = nullptr ;
123+ int64_t signedFlags = 0 ;
124+ if (napi_coerce_to_number (env, argv[1 ], &coercedFlags) != napi_ok ||
125+ napi_get_value_int64 (env, coercedFlags, &signedFlags) != napi_ok) {
126+ napi_throw_type_error (env, nullptr , " dispatch_get_global_queue expects numeric flags." );
127+ return nullptr ;
128+ }
129+ flags = static_cast <uint64_t >(signedFlags);
130+ }
131+ }
132+
133+ return createCompatDispatchQueueWrapperForCFunction (
134+ env, dispatch_get_global_queue (identifier, flags));
135+ }
136+
137+ if (strcmp (functionName, " dispatch_get_current_queue" ) == 0 ) {
138+ #pragma clang diagnostic push
139+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
140+ return createCompatDispatchQueueWrapperForCFunction (env, dispatch_get_current_queue ());
141+ #pragma clang diagnostic pop
142+ }
143+
144+ if (strcmp (functionName, " dispatch_async" ) == 0 ) {
145+ size_t argc = 2 ;
146+ napi_value argv[2 ] = {nullptr , nullptr };
147+ napi_get_cb_info (env, cbinfo, &argc, argv, nullptr , nullptr );
148+
149+ if (argc < 2 ) {
150+ napi_throw_type_error (env, nullptr , " dispatch_async expects a queue and callback." );
151+ return nullptr ;
152+ }
153+
154+ void * queueHandle = nullptr ;
155+ if (!unwrapCompatNativeHandleForCFunction (env, argv[0 ], &queueHandle) ||
156+ queueHandle == nullptr ) {
157+ napi_throw_type_error (env, nullptr , " dispatch_async expects a native queue handle." );
158+ return nullptr ;
159+ }
160+
161+ napi_valuetype callbackType = napi_undefined;
162+ if (napi_typeof (env, argv[1 ], &callbackType) != napi_ok || callbackType != napi_function) {
163+ napi_throw_type_error (env, nullptr , " dispatch_async expects a function callback." );
164+ return nullptr ;
165+ }
166+
167+ auto closure = new Closure (std::string (" v" ), true );
168+ closure->env = env;
169+ id block = registerBlock (env, closure, argv[1 ]);
170+ dispatch_block_t dispatchBlock = (dispatch_block_t )block;
171+
172+ dispatch_async (reinterpret_cast <dispatch_queue_t >(queueHandle), dispatchBlock);
173+ [block release ];
174+
175+ napi_value undefinedValue = nullptr ;
176+ napi_get_undefined (env, &undefinedValue);
177+ return undefinedValue;
178+ }
179+
180+ return nullptr ;
181+ }
182+
183+ } // namespace
184+
15185inline void ensureCFunctionDispatchLookup (CFunction* function, Cif* cif) {
16186 if (function == nullptr || cif == nullptr || cif->signatureHash == 0 ) {
17187 if (function != nullptr ) {
@@ -34,8 +204,7 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
34204 cif->signatureHash , SignatureCallKind::CFunction, function->dispatchFlags );
35205 function->preparedInvoker =
36206 reinterpret_cast <void *>(lookupCFunctionPreparedInvoker (function->dispatchId ));
37- function->napiInvoker =
38- reinterpret_cast <void *>(lookupCFunctionNapiInvoker (function->dispatchId ));
207+ function->napiInvoker = reinterpret_cast <void *>(lookupCFunctionNapiInvoker (function->dispatchId ));
39208 function->dispatchLookupCached = true ;
40209}
41210
@@ -90,15 +259,20 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
90259
91260 auto name = bridgeState->metadata ->getString (offset);
92261
262+ if (strcmp (name, " dispatch_async" ) == 0 || strcmp (name, " dispatch_get_current_queue" ) == 0 ||
263+ strcmp (name, " dispatch_get_global_queue" ) == 0 ) {
264+ return tryCallCompatLibdispatchFunction (env, cbinfo, name);
265+ }
266+
93267 auto func = bridgeState->getCFunction (env, offset);
94268
95269 auto cif = func->cif ;
96270 ensureCFunctionDispatchLookup (func, cif);
97271 auto preparedInvoker = reinterpret_cast <CFunctionPreparedInvoker>(func->preparedInvoker );
98272 auto napiInvoker = reinterpret_cast <CFunctionNapiInvoker>(func->napiInvoker );
99273
100- MDFunctionFlag functionFlags = bridgeState-> metadata -> getFunctionFlag (
101- offset + sizeof (MDSectionOffset) * 2 );
274+ MDFunctionFlag functionFlags =
275+ bridgeState-> metadata -> getFunctionFlag ( offset + sizeof (MDSectionOffset) * 2 );
102276
103277 const napi_value* invocationArgs = nullptr ;
104278 std::vector<napi_value> dynamicArgs;
@@ -139,7 +313,7 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) {
139313 const bool isMainEntrypoint =
140314 strcmp (name, " UIApplicationMain" ) == 0 || strcmp (name, " NSApplicationMain" ) == 0 ;
141315
142- if (napiInvoker != nullptr && !isMainEntrypoint) {
316+ if (napiInvoker != nullptr && !cif-> skipGeneratedNapiDispatch && ! isMainEntrypoint) {
143317 @try {
144318 if (!napiInvoker (env, cif, func->fnptr , invocationArgs, cif->rvalue )) {
145319 return nullptr ;
0 commit comments