@@ -906,6 +906,48 @@ bool TryFastSetV8ObjectReturnValue(napi_env env,
906906 return true ;
907907}
908908
909+ } // namespace
910+
911+ bool TryFastSetV8GeneratedObjCObjectReturnValue (
912+ napi_env env, const v8::FunctionCallbackInfo<v8::Value>& info, Cif* cif,
913+ void * bridgeState, id self, SEL selector, id value, bool returnOwned,
914+ bool receiverIsClass, bool propertyAccess) {
915+ (void )propertyAccess;
916+ auto * state = static_cast <ObjCBridgeState*>(bridgeState);
917+ if (env == nullptr || state == nullptr || cif == nullptr || cif->returnType == nullptr ) {
918+ return false ;
919+ }
920+
921+ if (selector == @selector (class )) {
922+ return false ;
923+ }
924+
925+ switch (cif->returnType ->kind ) {
926+ case mdTypeAnyObject:
927+ case mdTypeProtocolObject:
928+ case mdTypeClassObject:
929+ case mdTypeNSStringObject:
930+ break ;
931+ default :
932+ return false ;
933+ }
934+
935+ if (receiverIsClass && value != nil ) {
936+ Class receiverClass = (Class )self;
937+ if ((receiverClass == [NSString class ] || receiverClass == [NSMutableString class ]) &&
938+ (selector == @selector (string ) ||
939+ selector == @selector (stringWithString: ) ||
940+ selector == @selector (stringWithCapacity: ))) {
941+ return false ;
942+ }
943+ }
944+
945+ return TryFastSetV8ObjectReturnValue (
946+ env, info, state, value, returnOwned ? kOwnedObject : kUnownedObject );
947+ }
948+
949+ namespace {
950+
909951inline size_t alignUpSize (size_t value, size_t alignment) {
910952 if (alignment == 0 ) {
911953 return value;
@@ -1287,28 +1329,6 @@ CFunctionV8Invoker ensureCFunctionV8Invoker(CFunction* function, Cif* cif) {
12871329 return reinterpret_cast <CFunctionV8Invoker>(function->v8Invoker );
12881330}
12891331
1290- inline bool typeKindMayUseRoundTripCache (MDTypeKind kind) {
1291- switch (kind) {
1292- case mdTypeAnyObject:
1293- case mdTypeProtocolObject:
1294- case mdTypeClassObject:
1295- case mdTypeInstanceObject:
1296- case mdTypeNSStringObject:
1297- case mdTypeNSMutableStringObject:
1298- return true ;
1299- default :
1300- return false ;
1301- }
1302- }
1303-
1304- inline bool cifMayUseRoundTripCache (Cif* cif) {
1305- if (cif == nullptr ) {
1306- return false ;
1307- }
1308-
1309- return cif->returnType != nullptr && typeKindMayUseRoundTripCache (cif->returnType ->kind );
1310- }
1311-
13121332inline bool selectorEndsWith (SEL selector, const char * suffix) {
13131333 if (selector == nullptr || suffix == nullptr ) {
13141334 return false ;
@@ -2317,20 +2337,38 @@ bool invokeObjCFast(napi_env env, const v8::FunctionCallbackInfo<v8::Value>& inf
23172337 }
23182338 const bool hasImplicitNSErrorOutArg =
23192339 isNSErrorOutMethod && !cif->isVariadic && actualArgc + 1 == cif->argc ;
2320- if (!isNSErrorOutMethod && !requiresSuperCall &&
2321- tryInvokeObjCV8DirectFastPath (env, info, method, descriptor, cif, self)) {
2322- return true ;
2340+ const bool canUseGeneratedDispatch = !isNSErrorOutMethod && !requiresSuperCall;
2341+ ObjCV8Invoker invoker =
2342+ canUseGeneratedDispatch ? ensureObjCV8Invoker (cif, descriptor, descriptor->dispatchFlags )
2343+ : nullptr ;
2344+ if (invoker == nullptr ) {
2345+ if (canUseGeneratedDispatch &&
2346+ tryInvokeObjCV8DirectFastPath (env, info, method, descriptor, cif, self)) {
2347+ return true ;
2348+ }
2349+
2350+ return invokeObjCSlow (env, info, method, descriptor, cif, self, receiverIsClass,
2351+ propertyAccess);
23232352 }
23242353
2325- const bool needsRoundTripCache = cifMayUseRoundTripCache (cif);
2354+ const bool generatedDispatchSetsReturnDirectly =
2355+ cif->generatedDispatchSetsV8ReturnDirectly ;
2356+ const bool generatedDispatchUsesObjectReturnStorage =
2357+ !generatedDispatchSetsReturnDirectly && cif->generatedDispatchUsesObjectReturnStorage ;
2358+ const bool needsRoundTripCache =
2359+ generatedDispatchUsesObjectReturnStorage &&
2360+ cif->generatedDispatchHasRoundTripCacheArgument ;
23262361 std::optional<RoundTripCacheFrameGuard> roundTripCacheFrame;
23272362 if (needsRoundTripCache) {
23282363 roundTripCacheFrame.emplace (env, method->bridgeState );
23292364 }
23302365
23312366 std::optional<V8CifReturnStorage> rvalueStorage;
2367+ id objectRvalue = nil ;
23322368 void * rvalue = nullptr ;
2333- if (cif->returnType == nullptr || cif->returnType ->kind != mdTypeVoid) {
2369+ if (generatedDispatchUsesObjectReturnStorage) {
2370+ rvalue = &objectRvalue;
2371+ } else if (!generatedDispatchSetsReturnDirectly) {
23342372 rvalueStorage.emplace (cif);
23352373 if (!rvalueStorage->valid ()) {
23362374 throwV8Error (info.GetIsolate (),
@@ -2341,26 +2379,32 @@ bool invokeObjCFast(napi_env env, const v8::FunctionCallbackInfo<v8::Value>& inf
23412379 }
23422380
23432381 bool didInvoke = false ;
2344- ObjCV8Invoker invoker =
2345- requiresSuperCall ? nullptr : ensureObjCV8Invoker (cif, descriptor, descriptor->dispatchFlags );
2346- if (!isNSErrorOutMethod && invoker != nullptr ) {
2347- @try {
2348- didInvoke = invoker (env, cif, (void *)objc_msgSend, self, descriptor->selector , info, rvalue);
2349- } @catch (NSException * exception) {
2350- std::string message = exception.description .UTF8String ;
2351- NativeScriptException nativeScriptException (message);
2352- throwNativeScriptExceptionToV8 (env, info.GetIsolate (), nativeScriptException);
2353- return false ;
2354- }
2382+ bool didSetReturnValue = false ;
2383+ @try {
2384+ didInvoke = invoker (env, cif, (void *)objc_msgSend, self, descriptor->selector ,
2385+ method->bridgeState , method->returnOwned , receiverIsClass,
2386+ propertyAccess, info, rvalue, &didSetReturnValue);
2387+ } @catch (NSException * exception) {
2388+ std::string message = exception.description .UTF8String ;
2389+ NativeScriptException nativeScriptException (message);
2390+ throwNativeScriptExceptionToV8 (env, info.GetIsolate (), nativeScriptException);
2391+ return false ;
23552392 }
23562393
23572394 if (!didInvoke) {
2395+ if (canUseGeneratedDispatch &&
2396+ tryInvokeObjCV8DirectFastPath (env, info, method, descriptor, cif, self)) {
2397+ return true ;
2398+ }
2399+
23582400 return invokeObjCSlow (env, info, method, descriptor, cif, self, receiverIsClass,
23592401 propertyAccess);
23602402 }
23612403
2362- setObjCReturnValue (env, info, method, descriptor, cif, self, receiverIsClass, rvalue,
2363- propertyAccess);
2404+ if (!didSetReturnValue) {
2405+ setObjCReturnValue (env, info, method, descriptor, cif, self, receiverIsClass, rvalue,
2406+ propertyAccess);
2407+ }
23642408 return true ;
23652409}
23662410
@@ -2557,9 +2601,10 @@ void v8CFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
25572601 CFunctionV8Invoker invoker = ensureCFunctionV8Invoker (function, cif);
25582602
25592603 bool didInvoke = false ;
2604+ bool didSetReturnValue = false ;
25602605 if (invoker != nullptr ) {
25612606 @try {
2562- didInvoke = invoker (env, cif, function->fnptr , info, cif->rvalue );
2607+ didInvoke = invoker (env, cif, function->fnptr , info, cif->rvalue , &didSetReturnValue );
25632608 } @catch (NSException * exception) {
25642609 std::string message = exception.description .UTF8String ;
25652610 NativeScriptException nativeScriptException (message);
@@ -2573,7 +2618,9 @@ void v8CFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
25732618 return ;
25742619 }
25752620
2576- setCFunctionReturnValue (env, info, function, cif, cif->rvalue );
2621+ if (!didSetReturnValue) {
2622+ setCFunctionReturnValue (env, info, function, cif, cif->rvalue );
2623+ }
25772624}
25782625
25792626bool isCompatLibdispatchFunction (ObjCBridgeState* bridgeState, MDSectionOffset offset) {
0 commit comments