1#ifndef _OBJC_TEST_SUITE_NEXT_ENCODE_ASSIST_IMPL_H_
2#define _OBJC_TEST_SUITE_NEXT_ENCODE_ASSIST_IMPL_H_
3
4#ifdef __NEXT_RUNTIME__
5
6/* Determine which API to use.  */
7#include "next-abi.h"
8#ifdef NEXT_OBJC_USE_NEW_INTERFACE
9#include <objc/runtime.h>
10#else
11#include <objc/objc-runtime.h>
12#endif
13
14/* ---- */
15
16#undef  MAX
17#undef  MIN
18#undef  ROUND
19
20#ifdef __cplusplus
21#  define MAX(X, Y) ((X > Y) ? X : Y)
22#  define MIN(X, Y) ((X < Y) ? X : Y)
23#  define ROUND(V, A) (A * ((V + A - 1) / A))
24#else
25#  define MAX(X, Y)                    \
26  ({ typeof (X) __x = (X), __y = (Y); \
27     (__x > __y ? __x : __y); })
28#  define MIN(X, Y)                    \
29  ({ typeof (X) __x = (X), __y = (Y); \
30     (__x < __y ? __x : __y); })
31#  define ROUND(V, A) \
32  ({ typeof (V) __v = (V); typeof (A) __a = (A); \
33     __a * ((__v+__a - 1)/__a); })
34#endif
35
36#define BITS_PER_UNIT __CHAR_BIT__
37typedef struct{ char a; } __small_struct;
38#define STRUCTURE_SIZE_BOUNDARY (BITS_PER_UNIT * sizeof (__small_struct))
39
40/*
41  return the size of an object specified by type
42*/
43
44int
45objc_sizeof_type (const char *type)
46{
47  /* Skip the variable name if any */
48  if (*type == '"')
49    {
50      for (type++; *type++ != '"';)
51	/* do nothing */;
52    }
53
54  switch (*type) {
55  case _C_ID:
56    return sizeof (id);
57    break;
58
59  case _C_CLASS:
60    return sizeof (Class);
61    break;
62
63  case _C_SEL:
64    return sizeof (SEL);
65    break;
66
67  case _C_CHR:
68    return sizeof (char);
69    break;
70
71  case _C_UCHR:
72    return sizeof (unsigned char);
73    break;
74
75  case _C_SHT:
76    return sizeof (short);
77    break;
78
79  case _C_USHT:
80    return sizeof (unsigned short);
81    break;
82
83  case _C_INT:
84    return sizeof (int);
85    break;
86
87  case _C_UINT:
88    return sizeof (unsigned int);
89    break;
90
91  case _C_LNG:
92    return sizeof (long);
93    break;
94
95  case _C_ULNG:
96    return sizeof (unsigned long);
97    break;
98
99  case _C_LNG_LNG:
100    return sizeof (long long);
101    break;
102
103  case _C_ULNG_LNG:
104    return sizeof (unsigned long long);
105    break;
106
107  case _C_FLT:
108    return sizeof (float);
109    break;
110
111  case _C_DBL:
112    return sizeof (double);
113    break;
114
115  case _C_PTR:
116  case _C_ATOM:
117  case _C_CHARPTR:
118    return sizeof (char *);
119    break;
120
121  case _C_ARY_B:
122    {
123      int len = atoi (type + 1);
124      while (isdigit ((unsigned char)*++type))
125	;
126      return len * objc_aligned_size (type);
127    }
128    break;
129
130  case _C_BFLD:
131    {
132      /* The NeXT encoding of bitfields is _still_: b 'size' */
133      int size = atoi (type + 1);
134      /* Return an upper bound on byte size */
135      return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
136    }
137
138  case _C_STRUCT_B:
139    {
140      struct objc_struct_layout layout;
141      unsigned int size;
142
143      objc_layout_structure (type, &layout);
144      while (objc_layout_structure_next_member (&layout))
145        /* do nothing */ ;
146      objc_layout_finish_structure (&layout, &size, NULL);
147
148      return size;
149    }
150
151  case _C_UNION_B:
152    {
153      int max_size = 0;
154      while (*type != _C_UNION_E && *type++ != '=')
155	/* do nothing */;
156      while (*type != _C_UNION_E)
157	{
158	  /* Skip the variable name if any */
159	  if (*type == '"')
160	    {
161	      for (type++; *type++ != '"';)
162		/* do nothing */;
163	    }
164	  max_size = MAX (max_size, objc_sizeof_type (type));
165	  type = objc_skip_typespec (type);
166	}
167      return max_size;
168    }
169  }
170  return 0; /* error */
171}
172
173
174/*
175  Return the alignment of an object specified by type
176*/
177
178int
179objc_alignof_type (const char *type)
180{
181  /* Skip the variable name if any */
182  if (*type == '"')
183    {
184      for (type++; *type++ != '"';)
185	/* do nothing */;
186    }
187  switch (*type) {
188  case _C_ID:
189    return __alignof__ (id);
190    break;
191
192  case _C_CLASS:
193    return __alignof__ (Class);
194    break;
195
196  case _C_SEL:
197    return __alignof__ (SEL);
198    break;
199
200  case _C_CHR:
201    return __alignof__ (char);
202    break;
203
204  case _C_UCHR:
205    return __alignof__ (unsigned char);
206    break;
207
208  case _C_SHT:
209    return __alignof__ (short);
210    break;
211
212  case _C_USHT:
213    return __alignof__ (unsigned short);
214    break;
215
216  case _C_INT:
217  case _C_BFLD: /* This is for the NeXT only */
218    return __alignof__ (int);
219    break;
220
221  case _C_UINT:
222    return __alignof__ (unsigned int);
223    break;
224
225  case _C_LNG:
226    return __alignof__ (long);
227    break;
228
229  case _C_ULNG:
230    return __alignof__ (unsigned long);
231    break;
232
233  case _C_LNG_LNG:
234    return __alignof__ (long long);
235    break;
236
237  case _C_ULNG_LNG:
238    return __alignof__ (unsigned long long);
239    break;
240
241  case _C_FLT:
242    return __alignof__ (float);
243    break;
244
245  case _C_DBL:
246    return __alignof__ (double);
247    break;
248
249  case _C_PTR:
250  case _C_ATOM:
251  case _C_CHARPTR:
252    return __alignof__ (char *);
253    break;
254
255  case _C_ARY_B:
256    while (isdigit ((unsigned char)*++type))
257      /* do nothing */;
258    return objc_alignof_type (type);
259
260  case _C_STRUCT_B:
261    {
262      struct objc_struct_layout layout;
263      unsigned int align;
264
265      objc_layout_structure (type, &layout);
266      while (objc_layout_structure_next_member (&layout))
267        /* do nothing */;
268      objc_layout_finish_structure (&layout, NULL, &align);
269
270      return align;
271    }
272
273  case _C_UNION_B:
274    {
275      int maxalign = 0;
276      while (*type != _C_UNION_E && *type++ != '=')
277	/* do nothing */;
278      while (*type != _C_UNION_E)
279	{
280	  /* Skip the variable name if any */
281	  if (*type == '"')
282	    {
283	      for (type++; *type++ != '"';)
284		/* do nothing */;
285	    }
286	  maxalign = MAX (maxalign, objc_alignof_type (type));
287	  type = objc_skip_typespec (type);
288	}
289      return maxalign;
290    }
291  }
292  return 0; /* error */
293}
294
295/*
296  The aligned size if the size rounded up to the nearest alignment.
297*/
298
299int
300objc_aligned_size (const char *type)
301{
302  int size, align;
303
304  /* Skip the variable name */
305  if (*type == '"')
306    {
307      for (type++; *type++ != '"';)
308	/* do nothing */;
309    }
310
311  size = objc_sizeof_type (type);
312  align = objc_alignof_type (type);
313
314  return ROUND (size, align);
315}
316
317/*
318  The size rounded up to the nearest integral of the wordsize, taken
319  to be the size of a void *.
320*/
321
322int
323objc_promoted_size (const char *type)
324{
325  int size, wordsize;
326
327  /* Skip the variable name */
328  if (*type == '"')
329    {
330      for (type++; *type++ != '"';)
331	/* do nothing */;
332    }
333
334  size = objc_sizeof_type (type);
335  wordsize = sizeof (void *);
336
337  return ROUND (size, wordsize);
338}
339
340/*
341  Skip type qualifiers.  These may eventually precede typespecs
342  occurring in method prototype encodings.
343*/
344
345const char *
346objc_skip_type_qualifiers (const char *type)
347{
348  while (*type == _C_CONST
349	 || *type == _C_IN
350	 || *type == _C_INOUT
351	 || *type == _C_OUT
352	 || *type == _C_BYCOPY
353         || *type == _C_BYREF
354	 || *type == _C_ONEWAY
355	 || *type == _C_GCINVISIBLE)
356    {
357      type += 1;
358    }
359  return type;
360}
361
362/*
363  Skip one typespec element.  If the typespec is prepended by type
364  qualifiers, these are skipped as well.
365*/
366
367const char *
368objc_skip_typespec (const char *type)
369{
370  /* Skip the variable name if any */
371  if (*type == '"')
372    {
373      for (type++; *type++ != '"';)
374	/* do nothing */;
375    }
376
377  type = objc_skip_type_qualifiers (type);
378
379  switch (*type) {
380
381  case _C_ID:
382    /* An id may be annotated by the actual type if it is known
383       with the @"ClassName" syntax */
384
385    if (*++type != '"')
386      return type;
387    else
388      {
389	while (*++type != '"')
390	  /* do nothing */;
391	return type + 1;
392      }
393
394    /* The following are one character type codes */
395  case _C_CLASS:
396  case _C_SEL:
397  case _C_CHR:
398  case _C_UCHR:
399  case _C_CHARPTR:
400  case _C_ATOM:
401  case _C_SHT:
402  case _C_USHT:
403  case _C_INT:
404  case _C_UINT:
405  case _C_LNG:
406  case _C_ULNG:
407  case _C_LNG_LNG:
408  case _C_ULNG_LNG:
409  case _C_FLT:
410  case _C_DBL:
411  case _C_VOID:
412  case _C_UNDEF:
413    return ++type;
414    break;
415
416  case _C_ARY_B:
417    /* skip digits, typespec and closing ']' */
418
419    while (isdigit ((unsigned char)*++type))
420      ;
421    type = objc_skip_typespec (type);
422    if (*type == _C_ARY_E)
423      return ++type;
424    else
425      break; /* error */
426
427  case _C_BFLD:
428      /* The NeXT encoding for bitfields is _still_: b 'size' */
429    while (isdigit ((unsigned char)*++type))
430      ;	/* skip type and size */
431    return type;
432
433  case _C_STRUCT_B:
434    /* skip name, and elements until closing '}'  */
435
436    while (*type != _C_STRUCT_E && *type++ != '=')
437      ;
438    while (*type != _C_STRUCT_E)
439      {
440	type = objc_skip_typespec (type);
441      }
442    return ++type;
443
444  case _C_UNION_B:
445    /* skip name, and elements until closing ')'  */
446
447    while (*type != _C_UNION_E && *type++ != '=')
448      ;
449    while (*type != _C_UNION_E)
450      {
451	type = objc_skip_typespec (type);
452      }
453    return ++type;
454
455  case _C_PTR:
456    /* Just skip the following typespec */
457
458    return objc_skip_typespec (++type);
459  }
460  return 0; /* error */
461}
462
463/*
464  Skip an offset as part of a method encoding.  This is prepended by a
465  '+' if the argument is passed in registers.
466*/
467const char *
468objc_skip_offset (const char *type)
469{
470  if (*type == '+')
471    type++;
472  while (isdigit ((unsigned char) *++type))
473    ;
474  return type;
475}
476
477/*
478  Skip an argument specification of a method encoding.
479*/
480const char *
481objc_skip_argspec (const char *type)
482{
483  type = objc_skip_typespec (type);
484  type = objc_skip_offset (type);
485  return type;
486}
487
488unsigned
489objc_get_type_qualifiers (const char *type)
490{
491  unsigned res = 0;
492  BOOL flag = YES;
493
494  while (flag)
495    switch (*type++)
496      {
497      case _C_CONST:	res |= _F_CONST; break;
498      case _C_IN:	res |= _F_IN; break;
499      case _C_INOUT:	res |= _F_INOUT; break;
500      case _C_OUT:	res |= _F_OUT; break;
501      case _C_BYCOPY:	res |= _F_BYCOPY; break;
502      case _C_BYREF:  res |= _F_BYREF; break;
503      case _C_ONEWAY:	res |= _F_ONEWAY; break;
504      case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break;
505      default: flag = NO;
506    }
507
508  return res;
509}
510
511
512/* The following three functions can be used to determine how a
513   structure is laid out by the compiler. For example:
514
515  struct objc_struct_layout layout;
516  int i;
517
518  objc_layout_structure (type, &layout);
519  while (objc_layout_structure_next_member (&layout))
520    {
521      int position, align;
522      const char *type;
523
524      objc_layout_structure_get_info (&layout, &position, &align, &type);
525      printf ("element %d has offset %d, alignment %d\n",
526              i++, position, align);
527    }
528
529  These functions are used by objc_sizeof_type and objc_alignof_type
530  functions to compute the size and alignment of structures. The
531  previous method of computing the size and alignment of a structure
532  was not working on some architectures, particularly on AIX, and in
533  the presence of bitfields inside the structure. */
534void
535objc_layout_structure (const char *type,
536                           struct objc_struct_layout *layout)
537{
538  const char *ntype;
539
540  layout->original_type = ++type;
541
542  /* Skip "<name>=" if any. Avoid embedded structures and unions. */
543  ntype = type;
544  while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B
545         && *ntype++ != '=')
546    /* do nothing */;
547
548  /* If there's a "<name>=", ntype - 1 points to '='; skip the name */
549  if (*(ntype - 1) == '=')
550    type = ntype;
551
552  layout->type = type;
553  layout->prev_type = NULL;
554  layout->record_size = 0;
555  layout->record_align = MAX (BITS_PER_UNIT, STRUCTURE_SIZE_BOUNDARY);
556}
557
558BOOL
559objc_layout_structure_next_member (struct objc_struct_layout *layout)
560{
561  register int desired_align = 0;
562
563  /* The current type without the type qualifiers */
564  const char *type;
565
566  /* Add the size of the previous field to the size of the record.  */
567  if (layout->prev_type)
568    {
569      type = objc_skip_type_qualifiers (layout->prev_type);
570
571      if (*type != _C_BFLD)
572        layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT;
573      else
574	layout->record_size += atoi (++type);
575    }
576
577  if (*layout->type == _C_STRUCT_E)
578    return NO;
579
580  /* Skip the variable name if any */
581  if (*layout->type == '"')
582    {
583      for (layout->type++; *layout->type++ != '"';)
584        /* do nothing */;
585    }
586
587  type = objc_skip_type_qualifiers (layout->type);
588
589  desired_align = objc_alignof_type (type) * BITS_PER_UNIT;
590
591  /* Record must have at least as much alignment as any field.
592     Otherwise, the alignment of the field within the record
593     is meaningless.  */
594  layout->record_align = MAX (layout->record_align, desired_align);
595
596  if (*type == _C_BFLD)
597    {
598      int bfld_size = atoi (++type);
599      int int_align = __alignof__ (int) * BITS_PER_UNIT;
600      /* If this bitfield would traverse a word alignment boundary, push it out
601	 to that boundary instead.  */
602      if (layout->record_size % int_align
603	  && (layout->record_size / int_align
604	      < (layout->record_size + bfld_size - 1) / int_align))
605	layout->record_size = ROUND (layout->record_size, int_align);
606    }
607  else if (layout->record_size % desired_align != 0)
608    {
609      /* We need to skip space before this field.
610         Bump the cumulative size to multiple of field alignment.  */
611      layout->record_size = ROUND (layout->record_size, desired_align);
612    }
613
614  /* Jump to the next field in record. */
615
616  layout->prev_type = layout->type;
617  layout->type = objc_skip_typespec (layout->type);      /* skip component */
618
619  return YES;
620}
621
622
623void objc_layout_finish_structure (struct objc_struct_layout *layout,
624                                   unsigned int *size,
625                                   unsigned int *align)
626{
627  if (layout->type && *layout->type == _C_STRUCT_E)
628    {
629      /* Round the size up to be a multiple of the required alignment */
630      layout->record_size = ROUND (layout->record_size, layout->record_align);
631      layout->type = NULL;
632    }
633  if (size)
634    *size = layout->record_size / BITS_PER_UNIT;
635  if (align)
636    *align = layout->record_align / BITS_PER_UNIT;
637}
638
639
640void objc_layout_structure_get_info (struct objc_struct_layout *layout,
641                                     unsigned int *offset,
642                                     unsigned int *align,
643                                     const char **type)
644{
645  if (offset)
646    *offset = layout->record_size / BITS_PER_UNIT;
647  if (align)
648    *align = layout->record_align / BITS_PER_UNIT;
649  if (type)
650    *type = layout->prev_type;
651}
652
653#endif /* __NEXT_RUNTIME__ */
654#endif /* _OBJC_TEST_SUITE_NEXT_ENCODE_ASSIST_IMPL_H_ */
655