/ NSObjCRuntime.m
NSObjCRuntime.m
1 // 2 // NSObjCRuntime.m 3 // CoreFoundation 4 // 5 // Copyright (c) 2014 Apportable. All rights reserved. 6 // 7 8 #import <assert.h> 9 #import <objc/runtime.h> 10 11 #import <Foundation/NSException.h> 12 #import <Foundation/NSObjCRuntime.h> 13 #import <Foundation/NSString.h> 14 15 #import "NSObjCRuntimeInternal.h" 16 17 double NSFoundationVersionNumber = 1047.22; 18 19 // NSGetSizeAndAlignment does not allow for debugging sizes, like 20 // those emitted by method_getTypeEncoding, to occur in the type 21 // declaration ("i8" compared to just "i"). However, 22 // initWithObjCTypes: requires us to parse essentially the same 23 // format, but with the size hints, and so we let NSMethodSignature 24 // know this naughty little detail. 25 26 const char *__NSGetSizeAndAlignment(const char *decl, NSUInteger *size, NSUInteger *alignment, BOOL stripSizeHints) 27 { 28 decl = stripQualifiersAndComments(decl); 29 30 switch (*decl++) { 31 case _C_CHR: { 32 *size += sizeof(char); 33 *alignment = MAX(*alignment, __alignof(char)); 34 break; 35 } 36 37 case _C_SHT: { 38 *size += sizeof(short); 39 *alignment = MAX(*alignment, __alignof(short)); 40 break; 41 } 42 43 case _C_INT: { 44 *size += sizeof(int); 45 *alignment = MAX(*alignment, __alignof(int)); 46 break; 47 } 48 49 case _C_LNG: { 50 *size += sizeof(long); 51 *alignment = MAX(*alignment, __alignof(long)); 52 break; 53 } 54 55 case _C_LNG_LNG: { 56 *size += sizeof(long long); 57 *alignment = MAX(*alignment, __alignof(long long)); 58 break; 59 } 60 61 case _C_UCHR: { 62 *size += sizeof(unsigned char); 63 *alignment = MAX(*alignment, __alignof(unsigned char)); 64 break; 65 } 66 67 case _C_USHT: { 68 *size += sizeof(unsigned short); 69 *alignment = MAX(*alignment, __alignof(unsigned short)); 70 break; 71 } 72 73 case _C_UINT: { 74 *size += sizeof(unsigned int); 75 *alignment = MAX(*alignment, __alignof(unsigned int)); 76 break; 77 } 78 79 case _C_ULNG: { 80 *size += sizeof(unsigned long); 81 *alignment = MAX(*alignment, __alignof(unsigned long)); 82 break; 83 } 84 85 case _C_ULNG_LNG: { 86 *size += sizeof(unsigned long long); 87 *alignment = MAX(*alignment, __alignof(unsigned long long)); 88 break; 89 } 90 91 case _C_BOOL: { 92 *size += sizeof(BOOL); 93 *alignment = MAX(*alignment, __alignof(BOOL)); 94 break; 95 } 96 97 case _C_FLT: { 98 *size += sizeof(float); 99 *alignment = MAX(*alignment, __alignof(float)); 100 break; 101 } 102 103 case _C_DBL: { 104 *size += sizeof(double); 105 *alignment = MAX(*alignment, __alignof(double)); 106 break; 107 } 108 109 case _C_LNG_DBL: { 110 *size += sizeof(long double); 111 *alignment = MAX(*alignment, __alignof(long double)); 112 break; 113 } 114 115 case _C_VOID: { 116 // Apple claims a size and alignment of 0 for void. A 117 // GCCism does allow sizeof(void), but it doesn't do the 118 // right thing anyway. 119 break; 120 } 121 122 case _C_CHARPTR: { 123 *size += sizeof(char *); 124 *alignment += sizeof(char *); 125 break; 126 } 127 128 case _C_ID: { 129 *size += sizeof(id); 130 *alignment = MAX(*alignment, __alignof(id)); 131 if (decl[0] == _C_UNDEF) 132 { 133 ++decl; 134 } 135 break; 136 } 137 138 case _C_CLASS: { 139 *size += sizeof(Class); 140 *alignment = MAX(*alignment, __alignof(Class)); 141 break; 142 } 143 144 case _C_SEL: { 145 *size += sizeof(SEL); 146 *alignment = MAX(*alignment, __alignof(SEL)); 147 break; 148 } 149 150 case _C_PTR: { 151 *size += sizeof(void *); 152 *alignment = MAX(*alignment, __alignof(void *)); 153 if (decl[0] == _C_UNDEF) { 154 //special-case ^? - _C_UNDEF is an error anywhere but after a _C_PTR or _C_ID (if found in structs, it's just a ?, not a token) 155 ++decl; 156 } 157 else { 158 // All pointers are the same size, but we still have to 159 // consume the rest of the type. 160 NSUInteger dummy_size = 0; 161 NSUInteger dummy_alignment = 0; 162 decl = __NSGetSizeAndAlignment(decl, &dummy_size, &dummy_alignment, stripSizeHints); 163 } 164 break; 165 } 166 167 case _C_ARY_B: { 168 // strol() Just Works, as Apple does parse "[i]" as an array 169 // of 0 ints. They also only allow decimal sizes (no hex or 170 // any such thing). 171 size_t count = strtol((char *)decl, (char **)&decl, 10); 172 173 // The alignment is the same as the alignment of the member 174 // type. The size of an array is the count times the size of 175 // an array member, rounded up to a multiple of its alignment. 176 decl = __NSGetSizeAndAlignment(decl, size, alignment, stripSizeHints); 177 *size *= count; 178 179 // Consume the ']'. 180 ++decl; 181 break; 182 } 183 184 case _C_STRUCT_B: { 185 // The struct name is delineated either by '=', or by '}' for 186 // opaque types. 187 while (*decl != 0 && !strchr("=}", *decl)) { 188 decl++; 189 } 190 191 // Consume the '=' or '}'. 192 if (*(decl++) == _C_STRUCT_E) 193 { 194 break; 195 } 196 197 while (*decl != _C_STRUCT_E) { 198 NSUInteger field_size = 0; 199 NSUInteger field_alignment = 0; 200 decl = __NSGetSizeAndAlignment(decl, &field_size, &field_alignment, stripSizeHints); 201 202 // Align the field, by rounding *size up to a multiple of 203 // field_alignment. 204 if (field_size > 0) 205 { 206 size_t unalignment = *size % field_alignment; 207 208 if (unalignment > 0) 209 { 210 *size += field_alignment - unalignment; 211 } 212 } 213 214 // Add the size of the field, and possibly increase the 215 // alignment of the struct. 216 *size += field_size; 217 *alignment = MAX(*alignment, field_alignment); 218 } 219 220 // The size must be a multiple of the alignment. 221 if (*size > 0 && *alignment > 0) 222 { 223 size_t unalignment = *size % *alignment; 224 if (unalignment > 0) 225 { 226 *size += *alignment - unalignment; 227 } 228 } 229 230 // Consume the '}'. 231 ++decl; 232 break; 233 } 234 235 case _C_UNION_B: { 236 // The union name is delineated either by '=', or by ')' for 237 // opaque types. 238 while (*decl != 0 && !strchr("=)", *decl)) { 239 decl++; 240 } 241 242 // Consume the '=' or ')'. 243 if (*(decl++) == _C_UNION_E) 244 { 245 break; 246 } 247 248 while (*decl != _C_UNION_E) { 249 NSUInteger field_size = 0; 250 NSUInteger field_alignment = 0; 251 decl = __NSGetSizeAndAlignment(decl, &field_size, &field_alignment, stripSizeHints); 252 253 // The size and alignment are the maximum among all the fields. 254 *size = MAX(*size, field_size); 255 *alignment = MAX(*alignment, field_alignment); 256 } 257 258 // Consume the ')'. 259 ++decl; 260 break; 261 } 262 263 case _C_BFLD: // TODO throw an exception on bitfields. 264 case 'j': // Unsupported 265 default: { 266 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:nil userInfo:nil]; 267 } 268 } 269 270 if (stripSizeHints) 271 { 272 // Read off the advisory size. 273 strtol((char *)decl, (char **)&decl, 10); 274 } 275 276 return decl; 277 } 278 279 const char *NSGetSizeAndAlignment(const char *decl, NSUInteger *sizep, NSUInteger *alignp) 280 { 281 assert(decl != NULL); 282 283 NSUInteger size = 0; 284 NSUInteger alignment = 0; 285 286 if (*decl != '\0') 287 { 288 decl = __NSGetSizeAndAlignment(decl, &size, &alignment, NO); 289 } 290 291 if (sizep != NULL) { 292 *sizep = size; 293 } 294 295 if (alignp != NULL) { 296 *alignp = alignment; 297 } 298 299 return decl; 300 }