diff --git a/ext/obj_ext/RIGSCore.m b/ext/obj_ext/RIGSCore.m index 8cd75bb..64c6112 100644 --- a/ext/obj_ext/RIGSCore.m +++ b/ext/obj_ext/RIGSCore.m @@ -168,10 +168,6 @@ type = rb_objc_skip_type_qualifiers(type); - if (strcmp(type, "@?") == 0) { - return &ffi_type_pointer; - } - if (*type == _C_STRUCT_B) { inStructCount = rb_objc_struct_type_arity(type); @@ -191,6 +187,46 @@ return inStruct; } + if (*type == _C_ARY_B) { + while (isdigit((unsigned char)*++type)) { + inStructCount = (inStructCount << 3) + (inStructCount << 1) + (*type - '0'); + } + + inStruct = (ffi_type *)malloc(sizeof(ffi_type)); + inStruct->size = 0; + inStruct->alignment = 0; + inStruct->type = FFI_TYPE_STRUCT; + inStruct->elements = malloc((inStructCount + 1) * sizeof(ffi_type *)); + + while (*type != _C_ARY_E) { + inStruct->elements[inStructIndex++] = rb_objc_ffi_type_for_type(type); + type = rb_objc_skip_typespec(type); + } + inStruct->elements[inStructIndex] = NULL; + + return inStruct; + } + + if (*type == _C_BFLD) { + while (isdigit((unsigned char)*++type)) { + inStructCount = (inStructCount << 3) + (inStructCount << 1) + (*type - '0'); + if (*(type + 1) == _C_BFLD) type++; + } + + switch(inStructCount) { + case 64: + return &ffi_type_uint64; + case 32: + return &ffi_type_uint32; + case 16: + return &ffi_type_uint16; + case 8: + return &ffi_type_uint8; + default: + return NULL; + } + } + switch (*type) { case _C_ID: case _C_CLASS: @@ -213,10 +249,10 @@ return &ffi_type_uint; case _C_LNG: return &ffi_type_slong; - case _C_LNG_LNG: - return &ffi_type_sint64; case _C_ULNG: return &ffi_type_ulong; + case _C_LNG_LNG: + return &ffi_type_sint64; case _C_ULNG_LNG: return &ffi_type_uint64; case _C_FLT: @@ -618,6 +654,15 @@ object by calling rb_objc_release() */ type = rb_objc_skip_type_qualifiers(type); + // what if we made our own where by we dont + // offset (zero) when we encounter a bit field + // then we just keep bit masking the where? + // we'd need to know though to offset at the + // last one I think though... bummer... + // + // also is there like a max size we can + // support to just force the int size we + // bit mask with? say uint32_t? NSGetSizeAndAlignment(type, &tsize, &align); offset = ROUND(offset, align); @@ -781,97 +826,6 @@ object by calling rb_objc_release() */ } } -static NSMethodSignature* -rb_objc_signature_with_format_string(NSMethodSignature *signature, const char *formatString, int nbArgsExtra) -{ - char objcTypes[128]; - uint8_t objcTypesIndex; - size_t formatStringLength; - const char *type; - size_t nbArgs; - size_t i; - - nbArgs = [signature numberOfArguments]; - objcTypesIndex = 0; - - type = [signature methodReturnType]; - while (*type) { - objcTypes[objcTypesIndex++] = *type++; - } - - for(i=0; i 0) { - objcTypes[objcTypesIndex++] = _C_ID; - } - objcTypes[objcTypesIndex] = '\0'; - - return [NSMethodSignature signatureWithObjCTypes:objcTypes]; -} - static void rb_objc_proxy_handler(ffi_cif *cif, void *ret, void **args, void *user_data) { @autoreleasepool { @@ -969,26 +923,32 @@ object by calling rb_objc_release() */ int nbArgsExtra; int nbArgsAdjust; int i; - const char *type; void *data; void **args; VALUE rb_arg; VALUE rb_retval; - ffi_cif cif; ffi_type **arg_types; - ffi_type *ret_type; + ffi_type *type; + ffi_type *ret_type; + size_t len; + size_t ret_len; + const char *atypes; + const char *rtypes; + ffi_cif cif; ffi_closure *closure; ffi_status status; void *closurePtr; struct rb_objc_block *block; ffi_cif closureCif; - NSMethodSignature *signature; - - signature = [NSMethodSignature signatureWithObjCTypes:types]; - + NSInteger formatStringIndex; + const char *formatString; + const char *blockObjcTypes; + char *buf; + char keyChar; + if (rcv != nil) { nbArgsAdjust = 2; - switch(*(signature.methodReturnType)) { + switch(*types) { #ifndef __aarch64__ case _C_STRUCT_B: sym = objc_msgSend_stret; @@ -1008,17 +968,20 @@ object by calling rb_objc_release() */ return Qnil; } - nbArgs = (int)[signature numberOfArguments]; + ret_type = rb_objc_ffi_type_for_type(types); + ret_len = 0; + rtypes = types; + types = rb_objc_type_size(types, &ret_len); + ret_len = MAX(sizeof(long), ret_len); + + nbArgs = (int)rb_objc_type_arity(types); nbArgsExtra = rigs_argc - (nbArgs - nbArgsAdjust); if (nbArgsExtra < 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", rigs_argc, nbArgs - nbArgsAdjust); } - - if (nbArgsExtra > 0) { - NSInteger formatStringIndex; - const char *formatString; - + + if (nbArgsExtra > 0) { formatStringIndex = (NSInteger)NSMapGet(knownFormatStrings, (void*)hash) - 1; if (formatStringIndex != -1 && TYPE(rigs_argv[formatStringIndex]) == T_STRING) { formatString = rb_string_value_cstr(&rigs_argv[formatStringIndex]); @@ -1026,8 +989,24 @@ object by calling rb_objc_release() */ else { formatString = ""; } - signature = rb_objc_signature_with_format_string(signature, formatString, nbArgsExtra); - nbArgs = (int)[signature numberOfArguments]; + + buf = alloca(sizeof(char) * 255); + memset(buf, '\0', sizeof(char) * 255); + len = strlcpy(buf, types, strlen(types) + strlen(buf) + 1); + + i = nbArgsExtra; + while (len < 255 && (formatString = rb_objc_format_keychar(formatString, &keyChar))) { + buf[len++] = keyChar; + nbArgs++; + if (--i < 0) { + rb_raise(rb_eArgError, "too many tokens in the format string for the given argument(s)"); + } + } + while (len < 255 && i-- > 0) { + buf[len++] = _C_ID; + nbArgs++; + } + types = buf; } args = alloca(sizeof(void*) * nbArgs); @@ -1037,10 +1016,10 @@ object by calling rb_objc_release() */ memset(arg_types, 0, sizeof(ffi_type*) * nbArgs); for (i=0;i 0) { + // NSLog(@"%s %lu", thing, size); + // } + + // NSLog(@"%lu", size); + + // NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithString:@"3.14"]; + + // NSDecimal dec = [num decimalValue]; + + // {?=b8b4b1b1b18[8S]}16@0:8 + + // https://fuchsia.googlesource.com/third_party/swift-corelibs-foundation/+/refs/tags/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-10-06-a/Foundation/Decimal.swift + + // typedef struct { + // signed char exponent; // 8 - Signed exponent - -128 to 127 + // BOOL isNegative; // 4 - Is this negative? + // BOOL validNumber; // Is this a valid number? + // unsigned char length; // digits in mantissa. + // unsigned char cMantissa[2*NSDecimalMaxDigit]; + // } NSDecimal; + + // uint32_t bits = 0; + + // int32_t offsets[5] = { 8, 4, 1, 1, 18 }; + // int32_t values[5] = { -2, 1, 0, 1, 0 }; + // int32_t offset = 0; + + // for (int i=0; i<5; i++) { + // bits |= (((1 << offsets[i]) - 1) & values[i]) << offset; + // offset += offsets[i]; + // } + + // bits |= (((1 << 8) - 1) & -2) << 0; + // bits |= (((1 << 4) - 1) & 1) << 8; + // bits |= (((1 << 1) - 1) & 0) << 12; + // bits |= (((1 << 1) - 1) & 1) << 13; + // bits |= (((1 << 18) - 1) & 0) << 14; + + // unsigned short mantissa[8] = { 0 }; + // mantissa[0] = 314; + // mantissa[1] = 0; + // mantissa[2] = 0; + // mantissa[3] = 0; + // mantissa[4] = 0; + // mantissa[5] = 0; + // mantissa[6] = 0; + // mantissa[7] = 0; + + // void *data; + // data = malloc(sizeof(NSDecimal)); + // memset(data, 0, sizeof(NSDecimal)); + // memcpy(data, &bits, sizeof(uint32_t)); + // memcpy((uint8_t*)data + sizeof(uint32_t), &mantissa, sizeof(unsigned short) * 8); + + // dec = *(NSDecimal *)(data); + + // NSLog(@"%@", NSDecimalString(&dec, @".")); + + // size_t size = 0; + // NSGetSizeAndAlignment("[8S]", &size, NULL); + // NSLog(@"%s %lu %lu", @encode(BOOL*), size, sizeof(BOOL*)); + + // NSLog(@"%d", 31 >> 3); + + // bitfields + // NSNumber decimalValue {_NSDecimal=b8b4b1b1b18[8S]}@: YES + // DecimalNumber decimalNumberWithDecimal: @@:{_NSDecimal=b8b4b1b1b18[8S]} YES + // NSDecimalNumber decimalValue {_NSDecimal=b8b4b1b1b18[8S]}@: YES + // NSDecimalNumber initWithDecimal: @@:{_NSDecimal=b8b4b1b1b18[8S]} YES + // NSScanner scanDecimal: B@:^{_NSDecimal=b8b4b1b1b18[8S]} YES + + // consider loading (or backporting) + // QuartzCore -> CA* + // CoreFoundation -> CG* } diff --git a/ext/obj_ext/RIGSUtilities.h b/ext/obj_ext/RIGSUtilities.h index 5be64fb..b859083 100644 --- a/ext/obj_ext/RIGSUtilities.h +++ b/ext/obj_ext/RIGSUtilities.h @@ -44,10 +44,13 @@ unsigned long rb_objc_hash(const char *value); unsigned long rb_objc_hash_s(const char *value, unsigned long seed); unsigned long rb_objc_hash_struct(const char *value); unsigned long rb_objc_struct_type_arity(const char *type); +unsigned long rb_objc_type_arity(const char *type); const char *rb_objc_skip_type_qualifiers(const char *type); const char *rb_objc_skip_type_size(const char *type); const char *rb_objc_skip_type_sname(const char *type); const char *rb_objc_skip_type_uname(const char *type); const char *rb_objc_skip_typespec(const char *type); +const char *rb_objc_type_size(const char *type, size_t *size); +const char *rb_objc_format_keychar(const char *format, char *keyChar); #endif /* __RIGSUtilitis_h_GNUSTEP_RUBY_INCLUDE */ diff --git a/ext/obj_ext/RIGSUtilities.m b/ext/obj_ext/RIGSUtilities.m index e35f075..ac11ff4 100644 --- a/ext/obj_ext/RIGSUtilities.m +++ b/ext/obj_ext/RIGSUtilities.m @@ -272,6 +272,126 @@ return arity; } +unsigned long +rb_objc_type_arity(const char *type) +{ + unsigned long arity; + + arity = 0; + while((type = rb_objc_skip_typespec(type))) { + arity++; + } + + return arity; +} + + +const char * +rb_objc_type_size(const char *type, size_t *size) +{ + int count; + size_t tsize; + + count = 0; + tsize = 0; + type = rb_objc_skip_type_qualifiers(type); + + switch (*type) { + case _C_ID: + /* skip blocks */ + while (*++type == _C_UNDEF); + *size += sizeof(id); + return type; + case _C_CLASS: + *size += sizeof(Class); + return type + 1; + case _C_SEL: + *size += sizeof(SEL); + return type + 1; + case _C_BOOL: + *size += sizeof(BOOL); + return type + 1; + case _C_CHR: + *size += sizeof(char); + return type + 1; + case _C_UCHR: + *size += sizeof(unsigned char); + return type + 1; + case _C_CHARPTR: + case _C_ATOM: + *size += sizeof(char*); + return type + 1; + case _C_SHT: + *size += sizeof(short); + return type + 1; + case _C_USHT: + *size += sizeof(unsigned short); + return type + 1; + case _C_INT: + *size += sizeof(int); + return type + 1; + case _C_UINT: + *size += sizeof(unsigned int); + return type + 1; + case _C_LNG: + *size += sizeof(long); + return type + 1; + case _C_ULNG: + *size += sizeof(unsigned long); + return type + 1; + case _C_LNG_LNG: + *size += sizeof(long long); + return type + 1; + case _C_ULNG_LNG: + *size += sizeof(unsigned long long); + return type + 1; + case _C_FLT: + *size += sizeof(float); + return type + 1; + case _C_DBL: + *size += sizeof(double); + return type + 1; + case _C_VOID: + case _C_UNDEF: + return type + 1; + case _C_BFLD: + /* skip marker, sum bits until first non-marker */ + while (isdigit((unsigned char)*++type)) { + count = (count << 3) + (count << 1) + (*type - '0'); + if (*(type + 1) == _C_BFLD) type++; + } + *size += count >> 3; + return type; + case _C_ARY_B: + /* skip marker, multiply count by size elements until closing ']' */ + while (isdigit((unsigned char)*++type)) + count = (count << 3) + (count << 1) + (*type - '0'); + while (*type != _C_ARY_E) + type = rb_objc_type_size(type, &tsize); + *size += tsize * count; + return type + 1; + case _C_STRUCT_B: + /* skip name, size elements until closing '}' */ + type = rb_objc_skip_type_sname(type); + while (*type != _C_STRUCT_E) + type = rb_objc_type_size(type, size); + return type + 1; + case _C_UNION_B: + /* skip name, size elements until closing ')' */ + type = rb_objc_skip_type_uname(type); + while (*type != _C_UNION_E) + type = rb_objc_type_size(type, size); + return type + 1; + case _C_PTR: + /* skip the following typespec */ + type = rb_objc_skip_typespec(type + 1); + *size += sizeof(void*); + return type; + default: + return 0; + } +} + const char * rb_objc_skip_typespec(const char *type) { @@ -280,7 +400,7 @@ switch (*type) { case _C_ID: - /* skip blocks */; + /* skip blocks */ while (*++type == _C_UNDEF); return type; @@ -309,6 +429,8 @@ case _C_BFLD: /* skip number of bits */ while (isdigit((unsigned char)*++type)); + while (*type == _C_BFLD) + type = rb_objc_skip_typespec(type); return type; case _C_ARY_B: @@ -340,3 +462,58 @@ return 0; } } + +const char * +rb_objc_format_keychar(const char *format, char *keyChar) +{ + char fmtChar; + + while ((fmtChar = *format++)) { + if (fmtChar != '%') continue; + if (*format == '%') { + format++; + continue; + } + while ((fmtChar = *format++)) { + switch(fmtChar) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + case 'C': + *keyChar = _C_INT; + return format; + case 'D': + case 'O': + case 'U': + *keyChar = _C_LNG; + return format; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + *keyChar = _C_DBL; + return format; + case 's': + case 'S': + *keyChar = _C_CHARPTR; + return format; + case 'p': + *keyChar = _C_PTR; + return format; + case '@': + *keyChar = _C_ID; + return format; + } + } + } + + return 0; +}