4848// Hash table that maps known ObjC functions to objcTypes encoding
4949static NSMapTable *knownFunctions = 0 ;
5050
51- // Hash table that maps known ObjC selectors to block objcTypes encoding
52- static NSMapTable *knownBlocks = 0 ;
51+ // Hash table that maps known ObjC selectors with arg position to block objcTypes encoding
52+ static NSMapTable *knownBlockArgs = 0 ;
53+
54+ // Hash table that maps known ObjC selectors with arg position to objcTypes encoding
55+ static NSMapTable *knownTypeArgs = 0 ;
5356
5457// Hash table that maps known ObjC selectors to objcTypes encoding
5558static NSMapTable *knownProtocols = 0 ;
154157rb_objc_ffi_type_for_type (const char *type)
155158{
156159 ffi_type *inStruct = NULL ;
157- unsigned long inStructHash;
158160 int inStructIndex = 0 ;
159- long inStructCount = 0 ;
161+ unsigned long inStructCount = 0 ;
160162
161163 type = rb_objc_skip_type_qualifiers (type);
162164
165167 }
166168
167169 if (*type == _C_STRUCT_B) {
168- inStructHash = rb_objc_hash_struct (type);
169- type = rb_objc_skip_type_sname (type);
170- inStructCount = rb_array_len (rb_struct_s_members ((VALUE)NSMapGet (knownStructs, (void *)inStructHash)));
171-
170+ inStructCount = rb_objc_struct_type_arity (type);
171+
172172 inStruct = (ffi_type *)malloc (sizeof (ffi_type));
173173 inStruct->size = 0 ;
174174 inStruct->alignment = 0 ;
175175 inStruct->type = FFI_TYPE_STRUCT;
176176 inStruct->elements = malloc ((inStructCount + 1 ) * sizeof (ffi_type *));
177-
177+
178+ type = rb_objc_skip_type_sname (type);
178179 while (*type != _C_STRUCT_E) {
179180 inStruct->elements [inStructIndex++] = rb_objc_ffi_type_for_type (type);
180181 type = rb_objc_skip_typespec (type);
192193 case _C_PTR:
193194 return &ffi_type_pointer;
194195 case _C_BOOL:
195- case _C_UCHR:
196- return &ffi_type_uchar;
197196 case _C_CHR:
198197 return &ffi_type_schar;
198+ case _C_UCHR:
199+ return &ffi_type_uchar;
199200 case _C_SHT:
200201 return &ffi_type_sshort;
201202 case _C_USHT:
@@ -575,12 +576,7 @@ object by calling rb_objc_release() */
575576 break ;
576577 }
577578
578- if (inStruct) {
579- // skip the component we have just processed
580- type = rb_objc_skip_typespec (type);
581- }
582-
583- } while (inStruct && *type != _C_STRUCT_E);
579+ } while (inStruct && (type = rb_objc_skip_typespec (type)) && *type != _C_STRUCT_E);
584580
585581 if (ret == NO ) {
586582 /* raise exception - Don't know how to handle this type of argument */
@@ -659,7 +655,6 @@ object by calling rb_objc_release() */
659655 break ;
660656
661657 case _C_CHR:
662- // Assume that if YES or NO then it's a BOOLean
663658 if (__OBJC_BOOL_IS_BOOL != 1 && *(char *)where == YES )
664659 rb_val = Qtrue;
665660 else if (__OBJC_BOOL_IS_BOOL != 1 && *(char *)where == NO )
@@ -760,15 +755,13 @@ object by calling rb_objc_release() */
760755 // the end of the running Ruby array
761756 rb_ary_push (end, rb_val);
762757 }
763- // skip the type of the component we have just processed
764- type = (char *)rb_objc_skip_typespec (type);
765758 } else {
766759 // We are not in a C structure so simply return the
767760 // Ruby value
768761 *rb_val_ptr = rb_val;
769762 }
770763
771- } while (inStruct && *type != _C_STRUCT_E);
764+ } while (inStruct && (type = rb_objc_skip_typespec (type)) && *type != _C_STRUCT_E);
772765
773766 if (end != Qnil && NSMapGet (knownStructs, (void *)inStructHash) != NULL ) {
774767 *rb_val_ptr = rb_struct_alloc ((VALUE)NSMapGet (knownStructs, (void *)inStructHash), end);
@@ -793,7 +786,7 @@ object by calling rb_objc_release() */
793786 nbArgs = [signature numberOfArguments ];
794787 objcTypesIndex = 0 ;
795788
796- type = [signature methodReturnType ];
789+ type = [signature methodReturnType ];
797790 while (*type) {
798791 objcTypes[objcTypesIndex++] = *type++;
799792 }
@@ -961,10 +954,9 @@ object by calling rb_objc_release() */
961954}
962955
963956static VALUE
964- rb_objc_dispatch (id rcv, const char *method, NSMethodSignature *signature , int rigs_argc, VALUE *rigs_argv)
957+ rb_objc_dispatch (id rcv, const char *method, unsigned long hash, const char *types , int rigs_argc, VALUE *rigs_argv)
965958{
966959 void *sym;
967- unsigned long hash;
968960 int nbArgs;
969961 int nbArgsExtra;
970962 int nbArgsAdjust;
@@ -982,9 +974,14 @@ object by calling rb_objc_release() */
982974 void *closurePtr;
983975 struct rb_objc_block *block;
984976 ffi_cif closureCif;
977+ NSMethodSignature *signature;
978+
979+ signature = [NSMethodSignature signatureWithObjCTypes: types];
980+ if (!signature) {
981+ rb_raise (rb_eTypeError, " selector %s is missing an Objective-C signature" , method);
982+ }
985983
986984 if (rcv != nil ) {
987- // TODO: perhaps check [rcv methodForSelector:sel] for IMP
988985 nbArgsAdjust = 2 ;
989986 switch (*(signature.methodReturnType )) {
990987#ifndef __aarch64__
@@ -1006,8 +1003,6 @@ object by calling rb_objc_release() */
10061003 return Qnil;
10071004 }
10081005
1009- hash = rb_objc_hash (method);
1010-
10111006 nbArgs = (int )[signature numberOfArguments ];
10121007 nbArgsExtra = rigs_argc - (nbArgs - nbArgsAdjust);
10131008
@@ -1058,7 +1053,7 @@ object by calling rb_objc_release() */
10581053 for (i=nbArgsAdjust;i<nbArgs;i++) {
10591054 type = [signature getArgumentTypeAtIndex: i];
10601055 if (strcmp (type, " @?" ) == 0 ) {
1061- const char * blockObjcTypes = NSMapGet (knownBlocks , (void *)(hash + i - nbArgsAdjust));
1056+ const char * blockObjcTypes = NSMapGet (knownBlockArgs , (void *)(hash + i - nbArgsAdjust));
10621057 if (blockObjcTypes && rb_objc_build_closure_cif (&closureCif, blockObjcTypes) == FFI_OK) {
10631058 closure = ffi_closure_alloc (sizeof (ffi_closure), &closurePtr);
10641059 if (ffi_prep_closure_loc (closure, &closureCif, rb_objc_block_handler, &rigs_argv[i-nbArgsAdjust], closurePtr) == FFI_OK) {
@@ -1137,17 +1132,24 @@ object by calling rb_objc_release() */
11371132rb_objc_send (int rigs_argc, VALUE *rigs_argv, VALUE rb_self)
11381133{
11391134 @autoreleasepool {
1140- const char *method ;
1135+ const char *our_method ;
11411136 int our_argc;
11421137 VALUE *our_argv;
11431138 id rcv;
11441139 SEL sel;
1145- NSMethodSignature *signature;
1140+ const char *method;
1141+ const char *pos;
1142+ const char *lpos;
1143+ const char *type;
1144+ unsigned long typeIndex;
1145+ unsigned long hash;
1146+ Method mth;
1147+ char types[128 ] = { ' \0 ' };
11461148
1147- method = rb_id2name (rb_frame_this_func ());
1149+ our_method = rb_id2name (rb_frame_this_func ());
11481150 our_argc = rigs_argc;
11491151 our_argv = rigs_argv;
1150-
1152+
11511153 if (rb_block_given_p ()) {
11521154 our_argc = rigs_argc + 1 ;
11531155 our_argv = alloca (our_argc * sizeof (VALUE));
@@ -1157,31 +1159,47 @@ object by calling rb_objc_release() */
11571159 our_argv[our_argc-1 ] = rb_block_proc ();
11581160 }
11591161
1162+ sel = rb_objc_method_to_sel (our_method, our_argc);
1163+ if (sel == NULL ) {
1164+ rb_raise (rb_eTypeError, " method %s is not a valid Objective-C selector" , method);
1165+ }
1166+
1167+ method = sel_getName (sel);
1168+ hash = rb_objc_hash (method);
1169+
11601170 /* determine the receiver type - Class or instance ? */
11611171 switch (TYPE (rb_self)) {
11621172 case T_DATA:
11631173 Data_Get_Struct (rb_self, void , rcv);
1174+ mth = class_getInstanceMethod (object_getClass (rcv), sel);
11641175 break ;
11651176 case T_CLASS:
11661177 rcv = (Class )NUM2LL (rb_iv_get (rb_self, " @objc_class" ));
1178+ mth = class_getClassMethod (rcv, sel);
11671179 break ;
11681180 default :
11691181 rb_raise (rb_eTypeError, " can't convert %" PRIsVALUE" into compatible objc_msgSend value" , rb_self);
11701182 break ;
11711183 }
11721184
1173- sel = rb_objc_method_to_sel (method, our_argc);
1174- if (sel == NULL ) {
1175- rb_raise (rb_eTypeError, " method %s is not a valid Objective-C selector" , method);
1176- }
1177-
1178- signature = [rcv methodSignatureForSelector: sel];
1179- if (!signature) {
1180- rb_raise (rb_eTypeError, " selector %s is missing an Objective-C signature" , sel_getName (sel));
1185+ pos = rb_objc_skip_type_qualifiers (method_getTypeEncoding (mth));
1186+ typeIndex = 0 ;
1187+ while ((lpos = pos) && (pos = rb_objc_skip_typespec (lpos))) {
1188+ if (typeIndex != 1 &&
1189+ typeIndex != 2 &&
1190+ (type = NSMapGet (knownTypeArgs, (void *)(hash + typeIndex == 0 ? -1 : typeIndex - 2 )))) {
1191+ strlcat (types, type, strlen (type) + strlen (types) + 1 );
1192+ }
1193+ else {
1194+ strlcat (types, lpos, pos - lpos + strlen (types) + 1 );
1195+ }
1196+ pos = rb_objc_skip_type_size (pos);
1197+ pos = rb_objc_skip_type_qualifiers (pos);
1198+ typeIndex++;
11811199 }
11821200
11831201 @try {
1184- return rb_objc_dispatch (rcv, sel_getName (sel), signature , our_argc, our_argv);
1202+ return rb_objc_dispatch (rcv, method, hash, types , our_argc, our_argv);
11851203 }
11861204 @catch (NSException *exception) {
11871205 rb_objc_raise_exception (exception);
@@ -1196,7 +1214,6 @@ object by calling rb_objc_release() */
11961214 const char *method;
11971215 unsigned long hash;
11981216 const char *objcTypes;
1199- NSMethodSignature *signature;
12001217
12011218 method = rb_id2name (rb_frame_this_func ());
12021219 hash = rb_objc_hash (method);
@@ -1206,14 +1223,8 @@ object by calling rb_objc_release() */
12061223 return Qnil;
12071224 }
12081225
1209- signature = [NSMethodSignature signatureWithObjCTypes: objcTypes];
1210-
1211- if (!signature) {
1212- return Qnil;
1213- }
1214-
12151226 @try {
1216- return rb_objc_dispatch (nil , method, signature , rigs_argc, rigs_argv);
1227+ return rb_objc_dispatch (nil , method, hash, objcTypes , rigs_argc, rigs_argv);
12171228 }
12181229 @catch (NSException *exception) {
12191230 rb_objc_raise_exception (exception);
@@ -1363,33 +1374,6 @@ object by calling rb_objc_release() */
13631374 rb_define_const (rb_mRigs, name, rb_integer);
13641375}
13651376
1366- void
1367- rb_objc_register_block_from_objc (const char *selector, size_t index, const char *objcTypes)
1368- {
1369- unsigned long hash;
1370- char *data;
1371-
1372- hash = rb_objc_hash (selector) + index;
1373-
1374- if (!NSMapGet (knownBlocks, (void *)hash)) {
1375- data = malloc (sizeof (char ) * (strlen (objcTypes) + 1 ));
1376- strcpy (data, objcTypes);
1377- NSMapInsertKnownAbsent (knownBlocks, (void *)hash, (void *)data);
1378- }
1379- }
1380-
1381- void
1382- rb_objc_register_format_string_from_objc (const char *selector, size_t index)
1383- {
1384- unsigned long hash;
1385-
1386- hash = rb_objc_hash (selector);
1387-
1388- if (!NSMapGet (knownFormatStrings, (void *)hash)) {
1389- NSMapInsertKnownAbsent (knownFormatStrings, (void *)hash, (void *)(index + 1 ));
1390- }
1391- }
1392-
13931377void
13941378rb_objc_register_struct_from_objc (const char *key, const char *name, const char *args[], size_t argCount)
13951379{
@@ -1427,6 +1411,49 @@ object by calling rb_objc_release() */
14271411 NSMapInsertKnownAbsent (knownStructs, (void *)hash, (void *)rb_struct);
14281412}
14291413
1414+ void
1415+ rb_objc_register_type_arg_from_objc (const char *selector, size_t index, const char *objcTypes)
1416+ {
1417+ unsigned long hash;
1418+ char *data;
1419+
1420+ hash = rb_objc_hash (selector) + index;
1421+
1422+ if (!NSMapGet (knownTypeArgs, (void *)hash)) {
1423+ data = malloc (sizeof (char ) * (strlen (objcTypes) + 1 ));
1424+ strcpy (data, objcTypes);
1425+ NSMapInsertKnownAbsent (knownTypeArgs, (void *)hash, (void *)data);
1426+ }
1427+ }
1428+
1429+
1430+ void
1431+ rb_objc_register_block_arg_from_objc (const char *selector, size_t index, const char *objcTypes)
1432+ {
1433+ unsigned long hash;
1434+ char *data;
1435+
1436+ hash = rb_objc_hash (selector) + index;
1437+
1438+ if (!NSMapGet (knownBlockArgs, (void *)hash)) {
1439+ data = malloc (sizeof (char ) * (strlen (objcTypes) + 1 ));
1440+ strcpy (data, objcTypes);
1441+ NSMapInsertKnownAbsent (knownBlockArgs, (void *)hash, (void *)data);
1442+ }
1443+ }
1444+
1445+ void
1446+ rb_objc_register_format_string_from_objc (const char *selector, size_t index)
1447+ {
1448+ unsigned long hash;
1449+
1450+ hash = rb_objc_hash (selector);
1451+
1452+ if (!NSMapGet (knownFormatStrings, (void *)hash)) {
1453+ NSMapInsertKnownAbsent (knownFormatStrings, (void *)hash, (void *)(index + 1 ));
1454+ }
1455+ }
1456+
14301457VALUE
14311458rb_objc_register_class_from_objc (Class objc_class )
14321459{
@@ -1767,7 +1794,8 @@ void __attribute__((noreturn))
17671794 knownObjects = NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
17681795 knownStructs = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
17691796 knownFunctions = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
1770- knownBlocks = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
1797+ knownBlockArgs = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
1798+ knownTypeArgs = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
17711799 knownProtocols = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
17721800 knownImplementations = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSNonOwnedPointerMapValueCallBacks , 0 );
17731801 knownFormatStrings = NSCreateMapTable (NSIntegerMapKeyCallBacks , NSIntegerMapValueCallBacks , 0 );
0 commit comments