const char * objc_skip_argspec (const char *type) { type = objc_skip_typespec (type); type = objc_skip_offset (type); return type; }
/* objc_skip_argspec() is often buggy as it calls the buggy objc_skip_offset() * so we use a local version. */ static inline const char * skip_argspec(const char *types) { if (types && *types) { types = objc_skip_typespec(types); if (*types == '+') types++; while (isdigit(*types)) types++; } return types; }
char * method_get_next_argument (arglist_t argframe, const char **type) { const char *t = objc_skip_argspec (*type); if (*t == '\0') return 0; *type = t; t = objc_skip_typespec (t); if (*t == '+') return argframe->arg_regs + atoi (++t); else return argframe->arg_ptr + atoi (t); }
char* method_get_nth_argument (struct objc_method* m, arglist_t argframe, int arg, const char **type) { const char* t = objc_skip_argspec (m->method_types); if (arg > method_get_number_of_arguments (m)) return 0; while (arg--) t = objc_skip_argspec (t); *type = t; t = objc_skip_typespec (t); if (*t == '+') return argframe->arg_regs + atoi (++t); else return argframe->arg_ptr + atoi (t); }
inline const char * objc_skip_typespec (const char *type) { type = objc_skip_variable_name (type); type = objc_skip_type_qualifiers (type); switch (*type) { case _C_ID: /* An id may be annotated by the actual type if it is known with the @"ClassName" syntax */ if (*++type != '"') return type; else { while (*++type != '"') /* do nothing */; return type + 1; } /* The following are one character type codes */ case _C_CLASS: case _C_SEL: case _C_CHR: case _C_UCHR: case _C_CHARPTR: case _C_ATOM: case _C_SHT: case _C_USHT: case _C_INT: case _C_UINT: case _C_LNG: case _C_BOOL: case _C_ULNG: case _C_LNG_LNG: case _C_ULNG_LNG: case _C_FLT: case _C_DBL: case _C_LNG_DBL: case _C_VOID: case _C_UNDEF: return ++type; break; case _C_COMPLEX: return type + 2; break; case _C_ARY_B: /* skip digits, typespec and closing ']' */ while (isdigit ((unsigned char)*++type)) ; type = objc_skip_typespec (type); if (*type == _C_ARY_E) return ++type; else { _objc_abort ("bad array type %s\n", type); return 0; } case _C_VECTOR: /* Skip '!' */ type++; /* Skip '[' */ type++; /* Skip digits (size) */ while (isdigit ((unsigned char)*type)) type++; /* Skip ',' */ type++; /* Skip digits (alignment) */ while (isdigit ((unsigned char)*type)) type++; /* Skip typespec. */ type = objc_skip_typespec (type); /* Skip closing ']'. */ if (*type == _C_ARY_E) return ++type; else { _objc_abort ("bad vector type %s\n", type); return 0; } case _C_BFLD: /* The GNU encoding of bitfields is: b 'position' 'type' 'size'. */ while (isdigit ((unsigned char)*++type)) ; /* skip position */ while (isdigit ((unsigned char)*++type)) ; /* skip type and size */ return type; case _C_STRUCT_B: /* skip name, and elements until closing '}' */ while (*type != _C_STRUCT_E && *type++ != '=') ; while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); } return ++type; case _C_UNION_B: /* skip name, and elements until closing ')' */ while (*type != _C_UNION_E && *type++ != '=') ; while (*type != _C_UNION_E) { type = objc_skip_typespec (type); } return ++type; case _C_PTR: /* Just skip the following typespec */ return objc_skip_typespec (++type); default: { _objc_abort ("unknown type %s\n", type); return 0; } } }
BOOL objc_layout_structure_next_member (struct objc_struct_layout *layout) { register int desired_align = 0; /* The following are used only if the field is a bitfield */ register const char *bfld_type = 0; register int bfld_type_align = 0, bfld_field_size = 0; /* The current type without the type qualifiers */ const char *type; BOOL unionp = layout->original_type[-1] == _C_UNION_B; /* Add the size of the previous field to the size of the record. */ if (layout->prev_type) { type = objc_skip_type_qualifiers (layout->prev_type); if (unionp) layout->record_size = MAX (layout->record_size, objc_sizeof_type (type) * BITS_PER_UNIT); else if (*type != _C_BFLD) layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT; else { /* Get the bitfield's type */ for (bfld_type = type + 1; isdigit ((unsigned char)*bfld_type); bfld_type++) /* do nothing */; bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; bfld_field_size = atoi (objc_skip_typespec (bfld_type)); layout->record_size += bfld_field_size; } } if ((unionp && *layout->type == _C_UNION_E) || (!unionp && *layout->type == _C_STRUCT_E)) return NO; /* Skip the variable name if any */ layout->type = objc_skip_variable_name (layout->type); type = objc_skip_type_qualifiers (layout->type); if (*type != _C_BFLD) desired_align = objc_alignof_type (type) * BITS_PER_UNIT; else { desired_align = 1; /* Skip the bitfield's offset */ for (bfld_type = type + 1; isdigit ((unsigned char) *bfld_type); bfld_type++) /* do nothing */; bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; bfld_field_size = atoi (objc_skip_typespec (bfld_type)); } /* The following won't work for vectors. */ #ifdef BIGGEST_FIELD_ALIGNMENT desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT); #endif #ifdef ADJUST_FIELD_ALIGN desired_align = ADJUST_FIELD_ALIGN (type, desired_align); #endif /* Record must have at least as much alignment as any field. Otherwise, the alignment of the field within the record is meaningless. */ #ifndef HAVE_BITFIELD_TYPE_MATTERS layout->record_align = MAX (layout->record_align, desired_align); #else /* PCC_BITFIELD_TYPE_MATTERS */ if (*type == _C_BFLD) { /* For these machines, a zero-length field does not affect the alignment of the structure as a whole. It does, however, affect the alignment of the next field within the structure. */ if (bfld_field_size) layout->record_align = MAX (layout->record_align, desired_align); else desired_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; /* A named bit field of declared type `int' forces the entire structure to have `int' alignment. Q1: How is encoded this thing and how to check for it? Q2: How to determine maximum_field_alignment at runtime? */ /* if (DECL_NAME (field) != 0) */ { int type_align = bfld_type_align; #if 0 if (maximum_field_alignment != 0) type_align = MIN (type_align, maximum_field_alignment); else if (DECL_PACKED (field)) type_align = MIN (type_align, BITS_PER_UNIT); #endif layout->record_align = MAX (layout->record_align, type_align); } } else layout->record_align = MAX (layout->record_align, desired_align); #endif /* PCC_BITFIELD_TYPE_MATTERS */ /* Does this field automatically have alignment it needs by virtue of the fields that precede it and the record's own alignment? */ if (*type == _C_BFLD) layout->record_size = atoi (type + 1); else if (layout->record_size % desired_align != 0) { /* No, we need to skip space before this field. Bump the cumulative size to multiple of field alignment. */ layout->record_size = ROUND (layout->record_size, desired_align); } /* Jump to the next field in record. */ layout->prev_type = layout->type; layout->type = objc_skip_typespec (layout->type); /* skip component */ return YES; }
int objc_sizeof_type (const char* type) { /* Skip the variable name if any */ if (*type == '"') { for (type++; *type++ != '"';) /* do nothing */; } switch(*type) { case _C_ID: return sizeof(id); break; case _C_CLASS: return sizeof(Class); break; case _C_SEL: return sizeof(SEL); break; case _C_CHR: return sizeof(char); break; case _C_UCHR: return sizeof(unsigned char); break; case _C_SHT: return sizeof(short); break; case _C_USHT: return sizeof(unsigned short); break; case _C_INT: return sizeof(int); break; case _C_UINT: return sizeof(unsigned int); break; case _C_LNG: return sizeof(long); break; case _C_ULNG: return sizeof(unsigned long); break; case _C_LNG_LNG: return sizeof(long long); break; case _C_ULNG_LNG: return sizeof(unsigned long long); break; case _C_FLT: return sizeof(float); break; case _C_DBL: return sizeof(double); break; case _C_VOID: return sizeof(void); break; case _C_PTR: case _C_ATOM: case _C_CHARPTR: return sizeof(char*); break; case _C_ARY_B: { int len = atoi(type+1); while (isdigit(*++type)); return len*objc_aligned_size (type); } break; case _C_BFLD: { /* The new encoding of bitfields is: b 'position' 'type' 'size' */ int position, size; int startByte, endByte; position = atoi (type + 1); while (isdigit (*++type)); size = atoi (type + 1); startByte = position / BITS_PER_UNIT; endByte = (position + size) / BITS_PER_UNIT; return endByte - startByte; } case _C_STRUCT_B: { struct objc_struct_layout layout; unsigned int size; objc_layout_structure (type, &layout); while (objc_layout_structure_next_member (&layout)) /* do nothing */ ; objc_layout_finish_structure (&layout, &size, NULL); return size; } case _C_UNION_B: { int max_size = 0; while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; while (*type != _C_UNION_E) { /* Skip the variable name if any */ if (*type == '"') { for (type++; *type++ != '"';) /* do nothing */; } max_size = MAX (max_size, objc_sizeof_type (type)); type = objc_skip_typespec (type); } return max_size; } default: { objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); return 0; } } }
int method_get_sizeof_arguments (struct objc_method* mth) { const char* type = objc_skip_typespec (mth->method_types); return atoi (type); }
const char* objc_skip_typespec (const char* type) { /* Skip the variable name if any */ if (*type == '"') { for (type++; *type++ != '"';) /* do nothing */; } type = objc_skip_type_qualifiers (type); switch (*type) { case _C_ID: /* An id may be annotated by the actual type if it is known with the @"ClassName" syntax */ if (*++type != '"') return type; else { while (*++type != '"') /* do nothing */; return type + 1; } /* The following are one character type codes */ case _C_CLASS: case _C_SEL: case _C_CHR: case _C_UCHR: case _C_CHARPTR: case _C_ATOM: case _C_SHT: case _C_USHT: case _C_INT: case _C_UINT: case _C_LNG: case _C_ULNG: case _C_LNG_LNG: case _C_ULNG_LNG: case _C_FLT: case _C_DBL: case _C_VOID: case _C_UNDEF: return ++type; break; case _C_ARY_B: /* skip digits, typespec and closing ']' */ while(isdigit(*++type)); type = objc_skip_typespec(type); if (*type == _C_ARY_E) return ++type; else { objc_error(nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type); return 0; } case _C_BFLD: /* The new encoding of bitfields is: b 'position' 'type' 'size' */ while (isdigit (*++type)); /* skip position */ while (isdigit (*++type)); /* skip type and size */ return type; case _C_STRUCT_B: /* skip name, and elements until closing '}' */ while (*type != _C_STRUCT_E && *type++ != '='); while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); } return ++type; case _C_UNION_B: /* skip name, and elements until closing ')' */ while (*type != _C_UNION_E && *type++ != '='); while (*type != _C_UNION_E) { type = objc_skip_typespec (type); } return ++type; case _C_PTR: /* Just skip the following typespec */ return objc_skip_typespec (++type); default: { objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); return 0; } } }
int objc_alignof_type(const char* type) { /* Skip the variable name if any */ if (*type == '"') { for (type++; *type++ != '"';) /* do nothing */; } switch(*type) { case _C_ID: return __alignof__(id); break; case _C_CLASS: return __alignof__(Class); break; case _C_SEL: return __alignof__(SEL); break; case _C_CHR: return __alignof__(char); break; case _C_UCHR: return __alignof__(unsigned char); break; case _C_SHT: return __alignof__(short); break; case _C_USHT: return __alignof__(unsigned short); break; case _C_INT: return __alignof__(int); break; case _C_UINT: return __alignof__(unsigned int); break; case _C_LNG: return __alignof__(long); break; case _C_ULNG: return __alignof__(unsigned long); break; case _C_LNG_LNG: return __alignof__(long long); break; case _C_ULNG_LNG: return __alignof__(unsigned long long); break; case _C_FLT: return __alignof__(float); break; case _C_DBL: return __alignof__(double); break; case _C_PTR: case _C_ATOM: case _C_CHARPTR: return __alignof__(char*); break; case _C_ARY_B: while (isdigit(*++type)) /* do nothing */; return objc_alignof_type (type); case _C_STRUCT_B: { struct objc_struct_layout layout; unsigned int align; objc_layout_structure (type, &layout); while (objc_layout_structure_next_member (&layout)) /* do nothing */; objc_layout_finish_structure (&layout, NULL, &align); return align; } case _C_UNION_B: { int maxalign = 0; while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; while (*type != _C_UNION_E) { /* Skip the variable name if any */ if (*type == '"') { for (type++; *type++ != '"';) /* do nothing */; } maxalign = MAX (maxalign, objc_alignof_type (type)); type = objc_skip_typespec (type); } return maxalign; } default: { objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); return 0; } } }