@@ -41,6 +41,7 @@ explicit NativeApiRuntimeScope(Runtime&) {}
4141enum class NativeApiCallbackThreadPolicy {
4242 Default,
4343 JS ,
44+ Runtime,
4445};
4546
4647NativeApiCallbackThreadPolicy readEngineCallbackThreadPolicy (
@@ -58,6 +59,9 @@ NativeApiCallbackThreadPolicy readEngineCallbackThreadPolicy(
5859 if (policy == " js" ) {
5960 return NativeApiCallbackThreadPolicy::JS ;
6061 }
62+ if (policy == " runtime" || policy == " worklet" ) {
63+ return NativeApiCallbackThreadPolicy::Runtime;
64+ }
6165 } catch (const std::exception&) {
6266 }
6367 return NativeApiCallbackThreadPolicy::Default;
@@ -579,6 +583,7 @@ void invoke(void* ret, void* args[]) {
579583 std::string error;
580584 auto call = [&]() { invokeOnCurrentThread (ret, args, &error); };
581585 const auto & nativeCallbackInvoker = bridge_->nativeCallbackInvoker ();
586+ const auto & runtimeCallbackInvoker = bridge_->runtimeCallbackInvoker ();
582587 const auto & jsThreadCallbackInvoker = bridge_->jsThreadCallbackInvoker ();
583588 bool currentThreadIsJs =
584589 std::this_thread::get_id () == bridge_->jsThreadId ();
@@ -611,6 +616,17 @@ void invoke(void* ret, void* args[]) {
611616 }
612617 error = " Native callback was invoked off the JS thread without a JS scheduler." ;
613618 };
619+ auto callOnRuntimeThread = [&]() {
620+ if (currentThreadIsJs) {
621+ call ();
622+ return ;
623+ }
624+ if (runtimeCallbackInvoker) {
625+ runtimeCallbackInvoker (call);
626+ return ;
627+ }
628+ error = " Native callback was invoked off its owning runtime thread without a runtime scheduler." ;
629+ };
614630
615631 if (threadPolicy_ == NativeApiCallbackThreadPolicy::JS ) {
616632 callOnJSThread ();
@@ -621,20 +637,21 @@ void invoke(void* ret, void* args[]) {
621637 }
622638 return ;
623639 }
640+ if (threadPolicy_ == NativeApiCallbackThreadPolicy::Runtime) {
641+ callOnRuntimeThread ();
642+ if (!error.empty ()) {
643+ if (!recordNativeCallbackException (error)) {
644+ throwNativeApiCallbackException (error);
645+ }
646+ }
647+ return ;
648+ }
624649
625650 bool returnsVoid = signature_->returnType .kind == metagen::mdTypeVoid;
626- bool activeSynchronousNativeInvocation =
627- gActiveSynchronousNativeInvocationDepth .load (
628- std::memory_order_acquire) > 0 ;
629651 bool nativeCallerThreadCallbacks =
630652 bridge_->invokeCallbacksOnNativeCallerThread ();
631- bool nativeCallerThreadCallback =
632- nativeCallerThreadCallbacks && !currentThreadIsJs &&
633- activeSynchronousNativeInvocation &&
634- (block_ || bindThis_ || !returnsVoid);
635653 bool direct = currentThreadIsJs ||
636- gSynchronousNativeInvocationDepth > 0 ||
637- nativeCallerThreadCallback;
654+ gSynchronousNativeInvocationDepth > 0 ;
638655 bool waitForNativeThreadCallback =
639656 currentThreadIsJs && nativeCallbackInvoker &&
640657 gActiveNativeThreadEngineCallbacks .load (std::memory_order_acquire) > 0 ;
@@ -671,21 +688,14 @@ void invoke(void* ret, void* args[]) {
671688 return false ;
672689 };
673690
674- if (dispatchZeroArgVoidBlockAsync ()) {
691+ if (nativeCallerThreadCallbacks && !currentThreadIsJs) {
692+ callOnNativeCallerThread ();
693+ } else if (dispatchZeroArgVoidBlockAsync ()) {
675694 return ;
676- }
677-
678- if (direct && !waitForNativeThreadCallback) {
679- if (nativeCallerThreadCallback) {
680- callOnNativeCallerThread ();
681- } else {
682- call ();
683- }
684- } else if (!currentThreadIsJs && !nativeCallerThreadCallbacks) {
695+ } else if (direct && !waitForNativeThreadCallback) {
696+ call ();
697+ } else if (!currentThreadIsJs) {
685698 callOnJSThread ();
686- } else if (!currentThreadIsJs && returnsVoid && block_ &&
687- jsThreadCallbackInvoker) {
688- jsThreadCallbackInvoker (call);
689699 } else if (nativeCallbackInvoker) {
690700 bool nativeThreadCallback = !currentThreadIsJs;
691701 if (nativeThreadCallback) {
@@ -1472,6 +1482,31 @@ NativeApiType parseMetadataEngineType(MDMetadataReader* metadata,
14721482 return signature;
14731483}
14741484
1485+ bool prepareEngineCallbackSignature (NativeApiSignature* signature) {
1486+ if (signature == nullptr ) {
1487+ return false ;
1488+ }
1489+
1490+ signature->ffiTypes .clear ();
1491+ signature->ffiTypes .reserve (signature->argumentTypes .size () +
1492+ signature->implicitArgumentCount );
1493+ for (unsigned int i = 0 ; i < signature->implicitArgumentCount ; i++) {
1494+ signature->ffiTypes .push_back (&ffi_type_pointer);
1495+ }
1496+ for (const auto & argType : signature->argumentTypes ) {
1497+ signature->ffiTypes .push_back (ffiTypeForEngineArgument (argType));
1498+ }
1499+
1500+ ffi_status status = ffi_prep_cif (
1501+ &signature->cif , FFI_DEFAULT_ABI ,
1502+ static_cast <unsigned int >(signature->ffiTypes .size ()),
1503+ signature->returnType .ffiType != nullptr ? signature->returnType .ffiType
1504+ : &ffi_type_void,
1505+ signature->ffiTypes .empty () ? nullptr : signature->ffiTypes .data ());
1506+ signature->prepared = status == FFI_OK ;
1507+ return signature->prepared ;
1508+ }
1509+
14751510const char * skipObjCTypeQualifiers (const char * encoding) {
14761511 while (encoding != nullptr && *encoding != ' \0 ' &&
14771512 std::strchr (" rnNoORV" , *encoding) != nullptr ) {
@@ -1480,6 +1515,13 @@ NativeApiType parseMetadataEngineType(MDMetadataReader* metadata,
14801515 return encoding;
14811516}
14821517
1518+ const char * skipObjCTypeFrameOffset (const char * encoding) {
1519+ while (encoding != nullptr && *encoding >= ' 0' && *encoding <= ' 9' ) {
1520+ encoding++;
1521+ }
1522+ return encoding;
1523+ }
1524+
14831525const char * skipObjCTypeFieldName (const char * encoding, std::string* name) {
14841526 if (encoding == nullptr || *encoding != ' "' ) {
14851527 return encoding;
@@ -1930,6 +1972,48 @@ NativeApiType parseObjCEncodedEngineType(
19301972 return finishPrimitive (encoding + 1 );
19311973}
19321974
1975+ std::optional<NativeApiSignature> parseObjCCallbackEngineSignature (
1976+ const std::string& encodingString, bool block, NativeApiBridge* bridge) {
1977+ const char * cursor = skipObjCTypeQualifiers (encodingString.c_str ());
1978+ if (cursor == nullptr || *cursor == ' \0 ' ) {
1979+ return std::nullopt ;
1980+ }
1981+
1982+ NativeApiSignature signature;
1983+ signature.implicitArgumentCount = block ? 1 : 0 ;
1984+
1985+ const char * returnEnd = cursor;
1986+ signature.returnType = parseObjCEncodedEngineType (cursor, bridge, &returnEnd);
1987+ if (returnEnd == cursor) {
1988+ return std::nullopt ;
1989+ }
1990+ cursor = skipObjCTypeFrameOffset (returnEnd);
1991+
1992+ if (block) {
1993+ const char * blockSelf = skipObjCTypeQualifiers (cursor);
1994+ if (blockSelf != nullptr && blockSelf[0 ] == ' @' && blockSelf[1 ] == ' ?' ) {
1995+ cursor = skipObjCTypeFrameOffset (blockSelf + 2 );
1996+ }
1997+ }
1998+
1999+ while (cursor != nullptr && *cursor != ' \0 ' ) {
2000+ const char * argStart = skipObjCTypeQualifiers (cursor);
2001+ if (argStart == nullptr || *argStart == ' \0 ' ) {
2002+ break ;
2003+ }
2004+ const char * argEnd = argStart;
2005+ NativeApiType argType = parseObjCEncodedEngineType (argStart, bridge, &argEnd);
2006+ if (argEnd == argStart) {
2007+ return std::nullopt ;
2008+ }
2009+ signature.argumentTypes .push_back (std::move (argType));
2010+ cursor = skipObjCTypeFrameOffset (argEnd);
2011+ }
2012+
2013+ prepareEngineCallbackSignature (&signature);
2014+ return signature;
2015+ }
2016+
19332017std::optional<NativeApiSignature> parseObjCMethodEngineSignature (
19342018 Method method, NativeApiBridge* bridge = nullptr ) {
19352019 if (method == nullptr ) {
@@ -2110,6 +2194,36 @@ throw JSError(
21102194 return callback;
21112195}
21122196
2197+ std::shared_ptr<NativeApiCallback> createEngineCallback (
2198+ Runtime& runtime, const std::shared_ptr<NativeApiBridge>& bridge,
2199+ const std::string& objcSignatureEncoding, Function function, bool block,
2200+ NativeApiCallbackThreadPolicy threadPolicy =
2201+ NativeApiCallbackThreadPolicy::Default,
2202+ uintptr_t roundTripValidationKey = 0 ) {
2203+ if (bridge == nullptr || objcSignatureEncoding.empty ()) {
2204+ throw JSError (runtime, " Native callback encoding is unavailable." );
2205+ }
2206+
2207+ auto parsed = parseObjCCallbackEngineSignature (
2208+ objcSignatureEncoding, block, bridge.get ());
2209+ if (!parsed || !signatureSupportedForEngineCallback (*parsed)) {
2210+ throw JSError (
2211+ runtime, " Native callback signature is not supported by backend." );
2212+ }
2213+
2214+ auto signature =
2215+ std::make_shared<NativeApiSignature>(std::move (*parsed));
2216+ auto callback = std::make_shared<NativeApiCallback>(
2217+ runtime, bridge, std::move (signature), std::move (function), block,
2218+ threadPolicy, false , roundTripValidationKey);
2219+ if (block) {
2220+ callback->retainInitialBlockLifetime (callback);
2221+ } else {
2222+ bridge->retainEngineLifetime (callback);
2223+ }
2224+ return callback;
2225+ }
2226+
21132227std::shared_ptr<NativeApiCallback> createEngineMethodCallback (
21142228 Runtime& runtime, const std::shared_ptr<NativeApiBridge>& bridge,
21152229 const std::string& selectorName, MDSectionOffset signatureOffset,
0 commit comments