1/* Encoding of types for Objective C. 2 Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. 3 Contributed by Kresten Krab Thorup 4 Bitfield support by Ovidiu Predescu 5 6This file is part of GNU CC. 7 8GNU CC is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 2, or (at your option) 11any later version. 12 13GNU CC is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GNU CC; see the file COPYING. If not, write to 20the Free Software Foundation, 59 Temple Place - Suite 330, 21Boston, MA 02111-1307, USA. */ 22 23/* As a special exception, if you link this library with files 24 compiled with GCC to produce an executable, this does not cause 25 the resulting executable to be covered by the GNU General Public License. 26 This exception does not however invalidate any other reasons why 27 the executable file might be covered by the GNU General Public License. */ 28 29#include "tconfig.h" 30#include "objc-api.h" 31#include "encoding.h" 32 33#define MAX(X, Y) \ 34 ({ typeof(X) __x = (X), __y = (Y); \ 35 (__x > __y ? __x : __y); }) 36 37#define MIN(X, Y) \ 38 ({ typeof(X) __x = (X), __y = (Y); \ 39 (__x < __y ? __x : __y); }) 40 41#define ROUND(V, A) \ 42 ({ typeof(V) __v=(V); typeof(A) __a=(A); \ 43 __a*((__v+__a-1)/__a); }) 44 45 46/* Various hacks for objc_layout_record. These are used by the target 47 macros. */ 48 49#define TREE_CODE(TYPE) *TYPE 50#define TREE_TYPE(TREE) TREE 51 52#define RECORD_TYPE _C_STRUCT_B 53#define UNION_TYPE _C_UNION_B 54#define QUAL_UNION_TYPE _C_UNION_B 55#define ARRAY_TYPE _C_ARY_B 56 57#define TYPE_FIELDS(TYPE) objc_skip_typespec (TYPE) 58 59#define DECL_MODE(TYPE) *(TYPE) 60 61#define DFmode _C_DBL 62 63#define get_inner_array_type(TYPE) ((TYPE) + 1) 64 65 66static inline int 67atoi (const char* str) 68{ 69 int res = 0; 70 71 while (isdigit (*str)) 72 res *= 10, res += (*str++ - '0'); 73 74 return res; 75} 76 77/* 78 return the size of an object specified by type 79*/ 80 81int 82objc_sizeof_type (const char* type) 83{ 84 /* Skip the variable name if any */ 85 if (*type == '"') 86 { 87 for (type++; *type++ != '"';) 88 /* do nothing */; 89 } 90 91 switch(*type) { 92 case _C_ID: 93 return sizeof(id); 94 break; 95 96 case _C_CLASS: 97 return sizeof(Class); 98 break; 99 100 case _C_SEL: 101 return sizeof(SEL); 102 break; 103 104 case _C_CHR: 105 return sizeof(char); 106 break; 107 108 case _C_UCHR: 109 return sizeof(unsigned char); 110 break; 111 112 case _C_SHT: 113 return sizeof(short); 114 break; 115 116 case _C_USHT: 117 return sizeof(unsigned short); 118 break; 119 120 case _C_INT: 121 return sizeof(int); 122 break; 123 124 case _C_UINT: 125 return sizeof(unsigned int); 126 break; 127 128 case _C_LNG: 129 return sizeof(long); 130 break; 131 132 case _C_ULNG: 133 return sizeof(unsigned long); 134 break; 135 136 case _C_LNG_LNG: 137 return sizeof(long long); 138 break; 139 140 case _C_ULNG_LNG: 141 return sizeof(unsigned long long); 142 break; 143 144 case _C_FLT: 145 return sizeof(float); 146 break; 147 148 case _C_DBL: 149 return sizeof(double); 150 break; 151 152 case _C_VOID: 153 return sizeof(void); 154 break; 155 case _C_PTR: 156 case _C_ATOM: 157 case _C_CHARPTR: 158 return sizeof(char*); 159 break; 160 161 case _C_ARY_B: 162 { 163 int len = atoi(type+1); 164 while (isdigit(*++type)); 165 return len*objc_aligned_size (type); 166 } 167 break; 168 169 case _C_BFLD: 170 { 171 /* The new encoding of bitfields is: b 'position' 'type' 'size' */ 172 int position, size; 173 int startByte, endByte; 174 175 position = atoi (type + 1); 176 while (isdigit (*++type)); 177 size = atoi (type + 1); 178 179 startByte = position / BITS_PER_UNIT; 180 endByte = (position + size) / BITS_PER_UNIT; 181 return endByte - startByte; 182 } 183 184 case _C_STRUCT_B: 185 { 186 struct objc_struct_layout layout; 187 unsigned int size; 188 189 objc_layout_structure (type, &layout); 190 while (objc_layout_structure_next_member (&layout)) 191 /* do nothing */ ; 192 objc_layout_finish_structure (&layout, &size, NULL); 193 194 return size; 195 } 196 197 case _C_UNION_B: 198 { 199 int max_size = 0; 200 while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; 201 while (*type != _C_UNION_E) 202 { 203 /* Skip the variable name if any */ 204 if (*type == '"') 205 { 206 for (type++; *type++ != '"';) 207 /* do nothing */; 208 } 209 max_size = MAX (max_size, objc_sizeof_type (type)); 210 type = objc_skip_typespec (type); 211 } 212 return max_size; 213 } 214 215 default: 216 { 217 objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); 218 return 0; 219 } 220 } 221} 222 223 224/* 225 Return the alignment of an object specified by type 226*/ 227 228int 229objc_alignof_type(const char* type) 230{ 231 /* Skip the variable name if any */ 232 if (*type == '"') 233 { 234 for (type++; *type++ != '"';) 235 /* do nothing */; 236 } 237 switch(*type) { 238 case _C_ID: 239 return __alignof__(id); 240 break; 241 242 case _C_CLASS: 243 return __alignof__(Class); 244 break; 245 246 case _C_SEL: 247 return __alignof__(SEL); 248 break; 249 250 case _C_CHR: 251 return __alignof__(char); 252 break; 253 254 case _C_UCHR: 255 return __alignof__(unsigned char); 256 break; 257 258 case _C_SHT: 259 return __alignof__(short); 260 break; 261 262 case _C_USHT: 263 return __alignof__(unsigned short); 264 break; 265 266 case _C_INT: 267 return __alignof__(int); 268 break; 269 270 case _C_UINT: 271 return __alignof__(unsigned int); 272 break; 273 274 case _C_LNG: 275 return __alignof__(long); 276 break; 277 278 case _C_ULNG: 279 return __alignof__(unsigned long); 280 break; 281 282 case _C_LNG_LNG: 283 return __alignof__(long long); 284 break; 285 286 case _C_ULNG_LNG: 287 return __alignof__(unsigned long long); 288 break; 289 290 case _C_FLT: 291 return __alignof__(float); 292 break; 293 294 case _C_DBL: 295 return __alignof__(double); 296 break; 297 298 case _C_PTR: 299 case _C_ATOM: 300 case _C_CHARPTR: 301 return __alignof__(char*); 302 break; 303 304 case _C_ARY_B: 305 while (isdigit(*++type)) /* do nothing */; 306 return objc_alignof_type (type); 307 308 case _C_STRUCT_B: 309 { 310 struct objc_struct_layout layout; 311 unsigned int align; 312 313 objc_layout_structure (type, &layout); 314 while (objc_layout_structure_next_member (&layout)) 315 /* do nothing */; 316 objc_layout_finish_structure (&layout, NULL, &align); 317 318 return align; 319 } 320 321 case _C_UNION_B: 322 { 323 int maxalign = 0; 324 while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; 325 while (*type != _C_UNION_E) 326 { 327 /* Skip the variable name if any */ 328 if (*type == '"') 329 { 330 for (type++; *type++ != '"';) 331 /* do nothing */; 332 } 333 maxalign = MAX (maxalign, objc_alignof_type (type)); 334 type = objc_skip_typespec (type); 335 } 336 return maxalign; 337 } 338 339 default: 340 { 341 objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); 342 return 0; 343 } 344 } 345} 346 347/* 348 The aligned size if the size rounded up to the nearest alignment. 349*/ 350 351int 352objc_aligned_size (const char* type) 353{ 354 int size, align; 355 356 /* Skip the variable name */ 357 if (*type == '"') 358 { 359 for (type++; *type++ != '"';) 360 /* do nothing */; 361 } 362 363 size = objc_sizeof_type (type); 364 align = objc_alignof_type (type); 365 366 return ROUND (size, align); 367} 368 369/* 370 The size rounded up to the nearest integral of the wordsize, taken 371 to be the size of a void*. 372*/ 373 374int 375objc_promoted_size (const char* type) 376{ 377 int size, wordsize; 378 379 /* Skip the variable name */ 380 if (*type == '"') 381 { 382 for (type++; *type++ != '"';) 383 /* do nothing */; 384 } 385 386 size = objc_sizeof_type (type); 387 wordsize = sizeof (void*); 388 389 return ROUND (size, wordsize); 390} 391 392/* 393 Skip type qualifiers. These may eventually precede typespecs 394 occurring in method prototype encodings. 395*/ 396 397inline const char* 398objc_skip_type_qualifiers (const char* type) 399{ 400 while (*type == _C_CONST 401 || *type == _C_IN 402 || *type == _C_INOUT 403 || *type == _C_OUT 404 || *type == _C_BYCOPY 405 || *type == _C_BYREF 406 || *type == _C_ONEWAY 407 || *type == _C_GCINVISIBLE) 408 { 409 type += 1; 410 } 411 return type; 412} 413 414 415/* 416 Skip one typespec element. If the typespec is prepended by type 417 qualifiers, these are skipped as well. 418*/ 419 420const char* 421objc_skip_typespec (const char* type) 422{ 423 /* Skip the variable name if any */ 424 if (*type == '"') 425 { 426 for (type++; *type++ != '"';) 427 /* do nothing */; 428 } 429 430 type = objc_skip_type_qualifiers (type); 431 432 switch (*type) { 433 434 case _C_ID: 435 /* An id may be annotated by the actual type if it is known 436 with the @"ClassName" syntax */ 437 438 if (*++type != '"') 439 return type; 440 else 441 { 442 while (*++type != '"') /* do nothing */; 443 return type + 1; 444 } 445 446 /* The following are one character type codes */ 447 case _C_CLASS: 448 case _C_SEL: 449 case _C_CHR: 450 case _C_UCHR: 451 case _C_CHARPTR: 452 case _C_ATOM: 453 case _C_SHT: 454 case _C_USHT: 455 case _C_INT: 456 case _C_UINT: 457 case _C_LNG: 458 case _C_ULNG: 459 case _C_LNG_LNG: 460 case _C_ULNG_LNG: 461 case _C_FLT: 462 case _C_DBL: 463 case _C_VOID: 464 case _C_UNDEF: 465 return ++type; 466 break; 467 468 case _C_ARY_B: 469 /* skip digits, typespec and closing ']' */ 470 471 while(isdigit(*++type)); 472 type = objc_skip_typespec(type); 473 if (*type == _C_ARY_E) 474 return ++type; 475 else 476 { 477 objc_error(nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type); 478 return 0; 479 } 480 481 case _C_BFLD: 482 /* The new encoding of bitfields is: b 'position' 'type' 'size' */ 483 while (isdigit (*++type)); /* skip position */ 484 while (isdigit (*++type)); /* skip type and size */ 485 return type; 486 487 case _C_STRUCT_B: 488 /* skip name, and elements until closing '}' */ 489 490 while (*type != _C_STRUCT_E && *type++ != '='); 491 while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); } 492 return ++type; 493 494 case _C_UNION_B: 495 /* skip name, and elements until closing ')' */ 496 497 while (*type != _C_UNION_E && *type++ != '='); 498 while (*type != _C_UNION_E) { type = objc_skip_typespec (type); } 499 return ++type; 500 501 case _C_PTR: 502 /* Just skip the following typespec */ 503 504 return objc_skip_typespec (++type); 505 506 default: 507 { 508 objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type); 509 return 0; 510 } 511 } 512} 513 514/* 515 Skip an offset as part of a method encoding. This is prepended by a 516 '+' if the argument is passed in registers. 517*/ 518inline const char* 519objc_skip_offset (const char* type) 520{ 521 if (*type == '+') type++; 522 while(isdigit(*++type)); 523 return type; 524} 525 526/* 527 Skip an argument specification of a method encoding. 528*/ 529const char* 530objc_skip_argspec (const char* type) 531{ 532 type = objc_skip_typespec (type); 533 type = objc_skip_offset (type); 534 return type; 535} 536 537/* 538 Return the number of arguments that the method MTH expects. 539 Note that all methods need two implicit arguments `self' and 540 `_cmd'. 541*/ 542int 543method_get_number_of_arguments (struct objc_method* mth) 544{ 545 int i = 0; 546 const char* type = mth->method_types; 547 while (*type) 548 { 549 type = objc_skip_argspec (type); 550 i += 1; 551 } 552 return i - 1; 553} 554 555/* 556 Return the size of the argument block needed on the stack to invoke 557 the method MTH. This may be zero, if all arguments are passed in 558 registers. 559*/ 560 561int 562method_get_sizeof_arguments (struct objc_method* mth) 563{ 564 const char* type = objc_skip_typespec (mth->method_types); 565 return atoi (type); 566} 567 568/* 569 Return a pointer to the next argument of ARGFRAME. type points to 570 the last argument. Typical use of this look like: 571 572 { 573 char *datum, *type; 574 for (datum = method_get_first_argument (method, argframe, &type); 575 datum; datum = method_get_next_argument (argframe, &type)) 576 { 577 unsigned flags = objc_get_type_qualifiers (type); 578 type = objc_skip_type_qualifiers (type); 579 if (*type != _C_PTR) 580 [portal encodeData: datum ofType: type]; 581 else 582 { 583 if ((flags & _F_IN) == _F_IN) 584 [portal encodeData: *(char**)datum ofType: ++type]; 585 } 586 } 587 } 588*/ 589 590char* 591method_get_next_argument (arglist_t argframe, 592 const char **type) 593{ 594 const char *t = objc_skip_argspec (*type); 595 596 if (*t == '\0') 597 return 0; 598 599 *type = t; 600 t = objc_skip_typespec (t); 601 602 if (*t == '+') 603 return argframe->arg_regs + atoi (++t); 604 else 605 return argframe->arg_ptr + atoi (t); 606} 607 608/* 609 Return a pointer to the value of the first argument of the method 610 described in M with the given argumentframe ARGFRAME. The type 611 is returned in TYPE. type must be passed to successive calls of 612 method_get_next_argument. 613*/ 614char* 615method_get_first_argument (struct objc_method* m, 616 arglist_t argframe, 617 const char** type) 618{ 619 *type = m->method_types; 620 return method_get_next_argument (argframe, type); 621} 622 623/* 624 Return a pointer to the ARGth argument of the method 625 M from the frame ARGFRAME. The type of the argument 626 is returned in the value-result argument TYPE 627*/ 628 629char* 630method_get_nth_argument (struct objc_method* m, 631 arglist_t argframe, int arg, 632 const char **type) 633{ 634 const char* t = objc_skip_argspec (m->method_types); 635 636 if (arg > method_get_number_of_arguments (m)) 637 return 0; 638 639 while (arg--) 640 t = objc_skip_argspec (t); 641 642 *type = t; 643 t = objc_skip_typespec (t); 644 645 if (*t == '+') 646 return argframe->arg_regs + atoi (++t); 647 else 648 return argframe->arg_ptr + atoi (t); 649} 650 651unsigned 652objc_get_type_qualifiers (const char* type) 653{ 654 unsigned res = 0; 655 BOOL flag = YES; 656 657 while (flag) 658 switch (*type++) 659 { 660 case _C_CONST: res |= _F_CONST; break; 661 case _C_IN: res |= _F_IN; break; 662 case _C_INOUT: res |= _F_INOUT; break; 663 case _C_OUT: res |= _F_OUT; break; 664 case _C_BYCOPY: res |= _F_BYCOPY; break; 665 case _C_BYREF: res |= _F_BYREF; break; 666 case _C_ONEWAY: res |= _F_ONEWAY; break; 667 case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break; 668 default: flag = NO; 669 } 670 671 return res; 672} 673 674 675/* The following three functions can be used to determine how a 676 structure is laid out by the compiler. For example: 677 678 struct objc_struct_layout layout; 679 int i; 680 681 objc_layout_structure (type, &layout); 682 while (objc_layout_structure_next_member (&layout)) 683 { 684 int position, align; 685 const char *type; 686 687 objc_layout_structure_get_info (&layout, &position, &align, &type); 688 printf ("element %d has offset %d, alignment %d\n", 689 i++, position, align); 690 } 691 692 These functions are used by objc_sizeof_type and objc_alignof_type 693 functions to compute the size and alignment of structures. The 694 previous method of computing the size and alignment of a structure 695 was not working on some architectures, particulary on AIX, and in 696 the presence of bitfields inside the structure. */ 697void 698objc_layout_structure (const char *type, 699 struct objc_struct_layout *layout) 700{ 701 const char *ntype; 702 703 if (*type++ != _C_STRUCT_B) 704 { 705 objc_error(nil, OBJC_ERR_BAD_TYPE, 706 "record type expected in objc_layout_structure, got %s\n", 707 type); 708 } 709 710 layout->original_type = type; 711 712 /* Skip "<name>=" if any. Avoid embedded structures and unions. */ 713 ntype = type; 714 while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B 715 && *ntype++ != '=') 716 /* do nothing */; 717 718 /* If there's a "<name>=", ntype - 1 points to '='; skip the the name */ 719 if (*(ntype - 1) == '=') 720 type = ntype; 721 722 layout->type = type; 723 layout->prev_type = NULL; 724 layout->record_size = 0; 725 layout->record_align = BITS_PER_UNIT; 726 727#ifdef STRUCTURE_SIZE_BOUNDARY 728 layout->record_align = MAX (layout->record_align, STRUCTURE_SIZE_BOUNDARY); 729#endif 730} 731 732 733BOOL 734objc_layout_structure_next_member (struct objc_struct_layout *layout) 735{ 736 register int known_align = layout->record_size; 737 register int desired_align = 0; 738 739 /* The following are used only if the field is a bitfield */ 740 register const char *bfld_type; 741 register int bfld_type_size, bfld_type_align, bfld_field_size; 742 743 /* The current type without the type qualifiers */ 744 const char *type; 745 746#if 1 747 if (layout->prev_type == NULL) 748 { 749 layout->prev_type = layout->type; 750 layout->type = objc_skip_typespec (layout->prev_type); 751 return YES; 752 } 753#endif 754 755 /* Add the size of the previous field to the size of the record. */ 756 if (layout->prev_type) 757 { 758 type = objc_skip_type_qualifiers (layout->prev_type); 759 760 if (*type != _C_BFLD) 761 layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT; 762 else { 763 desired_align = 1; 764 /* Get the bitfield's type */ 765 for (bfld_type = type + 1; 766 isdigit(*bfld_type); 767 bfld_type++) 768 /* do nothing */; 769 770 bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT; 771 bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; 772 bfld_field_size = atoi (objc_skip_typespec (bfld_type)); 773 layout->record_size += bfld_field_size; 774 } 775 } 776 777 if (*layout->type == _C_STRUCT_E) 778 return NO; 779 780 /* Skip the variable name if any */ 781 if (*layout->type == '"') 782 { 783 for (layout->type++; *layout->type++ != '"';) 784 /* do nothing */; 785 } 786 787 type = objc_skip_type_qualifiers (layout->type); 788 789 if (*type != _C_BFLD) 790 desired_align = objc_alignof_type(type) * BITS_PER_UNIT; 791 else 792 { 793 desired_align = 1; 794 /* Skip the bitfield's offset */ 795 for (bfld_type = type + 1; isdigit(*bfld_type); bfld_type++) 796 /* do nothing */; 797 798 bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT; 799 bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; 800 bfld_field_size = atoi (objc_skip_typespec (bfld_type)); 801 } 802 803#ifdef BIGGEST_FIELD_ALIGNMENT 804 desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT); 805#endif 806#ifdef ADJUST_FIELD_ALIGN 807 desired_align = ADJUST_FIELD_ALIGN (type, desired_align); 808#endif 809 810 /* Record must have at least as much alignment as any field. 811 Otherwise, the alignment of the field within the record 812 is meaningless. */ 813#ifndef PCC_BITFIELD_TYPE_MATTERS 814 layout->record_align = MAX (layout->record_align, desired_align); 815#else 816 if (*type == _C_BFLD) 817 { 818 /* For these machines, a zero-length field does not 819 affect the alignment of the structure as a whole. 820 It does, however, affect the alignment of the next field 821 within the structure. */ 822 if (bfld_field_size) 823 layout->record_align = MAX (layout->record_align, desired_align); 824 else 825 desired_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; 826 827 /* A named bit field of declared type `int' 828 forces the entire structure to have `int' alignment. 829 Q1: How is encoded this thing and how to check for it? 830 Q2: How to determine maximum_field_alignment at runtime? */ 831 832/* if (DECL_NAME (field) != 0) */ 833 { 834 int type_align = bfld_type_align; 835#if 0 836 if (maximum_field_alignment != 0) 837 type_align = MIN (type_align, maximum_field_alignment); 838 else if (DECL_PACKED (field)) 839 type_align = MIN (type_align, BITS_PER_UNIT); 840#endif 841 842 layout->record_align = MAX (layout->record_align, type_align); 843 } 844 } 845 else 846 layout->record_align = MAX (layout->record_align, desired_align); 847#endif 848 849 /* Does this field automatically have alignment it needs 850 by virtue of the fields that precede it and the record's 851 own alignment? */ 852 853 if (*type == _C_BFLD) 854 layout->record_size = atoi (type + 1); 855 else if (layout->record_size % desired_align != 0) 856 { 857 /* No, we need to skip space before this field. 858 Bump the cumulative size to multiple of field alignment. */ 859 layout->record_size = ROUND (layout->record_size, desired_align); 860 } 861 862 /* Jump to the next field in record. */ 863 864 layout->prev_type = layout->type; 865 layout->type = objc_skip_typespec (layout->type); /* skip component */ 866 867 return YES; 868} 869 870 871void objc_layout_finish_structure (struct objc_struct_layout *layout, 872 unsigned int *size, 873 unsigned int *align) 874{ 875 if (layout->type && *layout->type == _C_STRUCT_E) 876 { 877 /* Work out the alignment of the record as one expression and store 878 in the record type. Round it up to a multiple of the record's 879 alignment. */ 880 881#ifdef ROUND_TYPE_ALIGN 882 layout->record_align = ROUND_TYPE_ALIGN (layout->original_type, 883 1, 884 layout->record_align); 885#else 886 layout->record_align = MAX (1, layout->record_align); 887#endif 888 889#ifdef ROUND_TYPE_SIZE 890 layout->record_size = ROUND_TYPE_SIZE (layout->original_type, 891 layout->record_size, 892 layout->record_align); 893#else 894 /* Round the size up to be a multiple of the required alignment */ 895 layout->record_size = ROUND (layout->record_size, layout->record_align); 896#endif 897 898 layout->type = NULL; 899 } 900 if (size) 901 *size = layout->record_size / BITS_PER_UNIT; 902 if (align) 903 *align = layout->record_align / BITS_PER_UNIT; 904} 905 906 907void objc_layout_structure_get_info (struct objc_struct_layout *layout, 908 unsigned int *offset, 909 unsigned int *align, 910 const char **type) 911{ 912 if (offset) 913 *offset = layout->record_size / BITS_PER_UNIT; 914 if (align) 915 *align = layout->record_align / BITS_PER_UNIT; 916 if (type) 917 *type = layout->prev_type; 918} 919