Skip to content

Commit 6a4cce2

Browse files
committed
Improve handling of structs
We have one spot where we need to build the FFI type for a struct and we don't need to know the name of it, just its arity and its individual types. This adds a utility function in order to check on that and uses it instead of checking knownStructs.
1 parent b861d1e commit 6a4cce2

5 files changed

Lines changed: 145 additions & 90 deletions

File tree

ext/obj_ext/RIGSBridgeSupportParser.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ - (void)finalizeArg
306306

307307
if (_blockIndex != -1) {
308308
if (_methodName) {
309-
rb_objc_register_block_from_objc([_methodName UTF8String], _blockIndex, [_objcTypes UTF8String]);
309+
rb_objc_register_block_arg_from_objc([_methodName UTF8String], _blockIndex, [_objcTypes UTF8String]);
310310
}
311311

312312
_blockIndex = -1;

ext/obj_ext/RIGSCore.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,12 @@ VALUE rb_objc_register_instance_method_from_rb(VALUE rb_class, VALUE rb_method);
4040
void rb_objc_register_float_from_objc(const char *name, double value);
4141
void rb_objc_register_integer_from_objc(const char *name, long long value);
4242
void rb_objc_register_struct_from_objc(const char *key, const char *name, const char *args[], size_t argCount);
43-
void rb_objc_register_format_string_from_objc(const char *selector, size_t index);
44-
void rb_objc_register_block_from_objc(const char *selector, size_t index, const char *objcTypes);
4543
void rb_objc_register_constant_from_objc(const char *name, const char *type);
4644
void rb_objc_register_function_from_objc(const char *name, const char *objcTypes);
4745
void rb_objc_register_protocol_from_objc(const char *selector, const char *objcTypes);
46+
void rb_objc_register_format_string_from_objc(const char *selector, size_t index);
47+
void rb_objc_register_type_arg_from_objc(const char *selector, size_t index, const char *objcTypes);
48+
void rb_objc_register_block_arg_from_objc(const char *selector, size_t index, const char *objcTypes);
4849

4950
VALUE rb_objc_import(VALUE rb_self, VALUE rb_name);
5051
VALUE rb_objc_new(int rigs_argc, VALUE *rigs_argv, VALUE rb_class);

ext/obj_ext/RIGSCore.m

Lines changed: 105 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@
4848
// Hash table that maps known ObjC functions to objcTypes encoding
4949
static 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
5558
static NSMapTable *knownProtocols = 0;
@@ -154,9 +157,8 @@
154157
rb_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

@@ -165,16 +167,15 @@
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);
@@ -192,10 +193,10 @@
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

963956
static 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() */
11371132
rb_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-
13931377
void
13941378
rb_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+
14301457
VALUE
14311458
rb_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);

ext/obj_ext/RIGSUtilities.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ char *rb_objc_sel_to_alias(SEL sel);
4242

4343
unsigned long rb_objc_hash(const char *value);
4444
unsigned long rb_objc_hash_struct(const char *value);
45+
unsigned long rb_objc_struct_type_arity(const char *type);
4546
const char *rb_objc_skip_type_qualifiers(const char *type);
47+
const char *rb_objc_skip_type_size(const char *type);
4648
const char *rb_objc_skip_type_sname(const char *type);
4749
const char *rb_objc_skip_typespec(const char *type);
4850

0 commit comments

Comments
 (0)