OSDN Git Service

This patch makes selectors in the Objective-C language be pointers
[pf3gnuchains/gcc-fork.git] / gcc / objc / encoding.c
1 /* Encoding of types for Objective C.
2    Copyright (C) 1993 Free Software Foundation, Inc.
3
4 Author: Kresten Krab Thorup
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
21
22 /* As a special exception, if you link this library with files
23    compiled with GCC to produce an executable, this does not cause
24    the resulting executable to be covered by the GNU General Public License.
25    This exception does not however invalidate any other reasons why
26    the executable file might be covered by the GNU General Public License.  */
27
28 #include "encoding.h"
29
30 #define MAX(X, Y)                    \
31   ({ typeof(X) __x = (X), __y = (Y); \
32      (__x > __y ? __x : __y); })
33
34 #define MIN(X, Y)                    \
35   ({ typeof(X) __x = (X), __y = (Y); \
36      (__x < __y ? __x : __y); })
37
38 #define ROUND(V, A) \
39   ({ typeof(V) __v=(V); typeof(A) __a=(A); \
40      __a*((__v+__a-1)/__a); })
41
42
43 static inline int
44 atoi (const char* str)
45 {
46   int res = 0;
47   
48   while (isdigit (*str))
49     res *= 10, res += (*str++ - '0');
50
51   return res;
52 }
53
54 /*
55   return the size of an object specified by type 
56 */
57
58 int
59 objc_sizeof_type(const char* type)
60 {
61   switch(*type) {
62   case _C_ID:
63     return sizeof(id);
64     break;
65
66   case _C_CLASS:
67     return sizeof(Class*);
68     break;
69
70   case _C_SEL:
71     return sizeof(SEL);
72     break;
73
74   case _C_CHR:
75     return sizeof(char);
76     break;
77     
78   case _C_UCHR:
79     return sizeof(unsigned char);
80     break;
81
82   case _C_SHT:
83     return sizeof(short);
84     break;
85
86   case _C_USHT:
87     return sizeof(unsigned short);
88     break;
89
90   case _C_INT:
91     return sizeof(int);
92     break;
93
94   case _C_UINT:
95     return sizeof(unsigned int);
96     break;
97
98   case _C_LNG:
99     return sizeof(long);
100     break;
101
102   case _C_ULNG:
103     return sizeof(unsigned long);
104     break;
105
106   case _C_PTR:
107   case _C_ATOM:
108   case _C_CHARPTR:
109     return sizeof(char*);
110     break;
111
112   case _C_ARY_B:
113     {
114       int len = atoi(type+1);
115       while (isdigit(*++type));
116       return len*objc_aligned_size (type);
117     }
118     break; 
119
120   case _C_STRUCT_B:
121     {
122       int acc_size = 0;
123       int align;
124       while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
125       while (*type != _C_STRUCT_E);
126         {
127           align = objc_alignof_type (type);       /* padd to alignment */
128           acc_size += ROUND (acc_size, align);
129           acc_size += objc_sizeof_type (type);   /* add component size */
130           type = objc_skip_typespec (type);              /* skip component */
131         }
132       return acc_size;
133     }
134
135   case _C_UNION_B:
136     {
137       int max_size = 0;
138       while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
139       while (*type != _C_UNION_E)
140         {
141           max_size = MAX (max_size, objc_sizeof_type (type));
142           type = objc_skip_typespec (type);
143         }
144       return max_size;
145     }
146     
147   default:
148     abort();
149   }
150 }
151
152
153 /*
154   Return the alignment of an object specified by type 
155 */
156
157 int
158 objc_alignof_type(const char* type)
159 {
160   switch(*type) {
161   case _C_ID:
162     return __alignof__(id);
163     break;
164
165   case _C_CLASS:
166     return __alignof__(Class*);
167     break;
168     
169   case _C_SEL:
170     return __alignof__(SEL);
171     break;
172
173   case _C_CHR:
174     return __alignof__(char);
175     break;
176     
177   case _C_UCHR:
178     return __alignof__(unsigned char);
179     break;
180
181   case _C_SHT:
182     return __alignof__(short);
183     break;
184
185   case _C_USHT:
186     return __alignof__(unsigned short);
187     break;
188
189   case _C_INT:
190     return __alignof__(int);
191     break;
192
193   case _C_UINT:
194     return __alignof__(unsigned int);
195     break;
196
197   case _C_LNG:
198     return __alignof__(long);
199     break;
200
201   case _C_ULNG:
202     return __alignof__(unsigned long);
203     break;
204
205   case _C_ATOM:
206   case _C_CHARPTR:
207     return __alignof__(char*);
208     break;
209
210   case _C_ARY_B:
211     while (isdigit(*++type)) /* do nothing */;
212     return objc_alignof_type (type);
213       
214   case _C_STRUCT_B:
215     {
216       struct { int x; double y; } fooalign;
217       while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */;
218       if (*type != _C_STRUCT_E)
219         return MAX (objc_alignof_type (type), __alignof__ (fooalign));
220       else
221         return __alignof__ (fooalign);
222     }
223
224   case _C_UNION_B:
225     {
226       int maxalign = 0;
227       while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
228       while (*type != _C_UNION_E)
229         {
230           maxalign = MAX (maxalign, objc_alignof_type (type));
231           type = objc_skip_typespec (type);
232         }
233       return maxalign;
234     }
235     
236   default:
237     abort();
238   }
239 }
240
241 /*
242   The aligned size if the size rounded up to the nearest alignment.
243 */
244
245 int
246 objc_aligned_size (const char* type)
247 {
248   int size = objc_sizeof_type (type);
249   int align = objc_alignof_type (type);
250   return ROUND (size, align);
251 }
252
253 /*
254   The size rounded up to the nearest integral of the wordsize, taken
255   to be the size of a void*.
256 */
257
258 int 
259 objc_promoted_size (const char* type)
260 {
261   int size = objc_sizeof_type (type);
262   int wordsize = sizeof (void*);
263
264   return ROUND (size, wordsize);
265 }
266
267 /*
268   Skip type qualifiers.  These may eventually precede typespecs
269   occuring in method prototype encodings.
270 */
271
272 inline const char*
273 objc_skip_type_qualifiers (const char* type)
274 {
275   while (*type == _C_CONST
276          || *type == _C_IN 
277          || *type == _C_INOUT
278          || *type == _C_OUT 
279          || *type == _C_BYCOPY
280          || *type == _C_ONEWAY)
281     {
282       type += 1;
283     }
284   return type;
285 }
286
287   
288 /*
289   Skip one typespec element.  If the typespec is prepended by type
290   qualifiers, these are skipped as well.
291 */
292
293 const char* 
294 objc_skip_typespec (const char* type)
295 {
296   type = objc_skip_type_qualifiers (type);
297   
298   switch (*type) {
299
300   case _C_ID:
301     /* An id may be annotated by the actual type if it is known
302        with the @"ClassName" syntax */
303
304     if (*++type != '"')
305       return type;
306     else
307       {
308         while (*++type != '"') /* do nothing */;
309         return type + 1;
310       }
311
312     /* The following are one character type codes */
313   case _C_CLASS:
314   case _C_SEL:
315   case _C_CHR:
316   case _C_UCHR:
317   case _C_CHARPTR:
318   case _C_ATOM:
319   case _C_SHT:
320   case _C_USHT:
321   case _C_INT:
322   case _C_UINT:
323   case _C_LNG:
324   case _C_ULNG:
325   case _C_FLT:
326   case _C_DBL:
327   case _C_VOID:
328     return ++type;
329     break;
330
331   case _C_ARY_B:
332     /* skip digits, typespec and closing ']' */
333     
334     while(isdigit(*++type));
335     type = objc_skip_typespec(type);
336     if (*type == _C_ARY_E)
337       return ++type;
338     else
339       abort();
340
341   case _C_STRUCT_B:
342     /* skip name, and elements until closing '}'  */
343     
344     while (*type != _C_STRUCT_E && *type++ != '=');
345     while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); }
346     return ++type;
347
348   case _C_UNION_B:
349     /* skip name, and elements until closing ')'  */
350     
351     while (*type != _C_UNION_E && *type++ != '=');
352     while (*type != _C_UNION_E) { type = objc_skip_typespec (type); }
353     return ++type;
354
355   case _C_PTR:
356     /* Just skip the following typespec */
357     
358     return objc_skip_typespec (++type);
359     
360   default:
361     abort();
362   }
363 }
364
365 /*
366   Skip an offset as part of a method encoding.  This is prepended by a
367   '+' if the argument is passed in registers.
368 */
369 inline const char* 
370 objc_skip_offset (const char* type)
371 {
372   if (*type == '+') type++;
373   while(isdigit(*++type));
374   return type;
375 }
376
377 /*
378   Skip an argument specification of a method encoding.
379 */
380 const char*
381 objc_skip_argspec (const char* type)
382 {
383   type = objc_skip_typespec (type);
384   type = objc_skip_offset (type);
385   return type;
386 }
387
388 /*
389   Return the number of arguments that the method MTH expects.
390   Note that all methods need two implicit arguments `self' and
391   `_cmd'. 
392 */
393 int
394 method_get_number_of_arguments (struct objc_method* mth)
395 {
396   int i = 0;
397   const char* type = mth->method_types;
398   while (*type)
399     {
400       type = objc_skip_argspec (type);
401       i += 1;
402     }
403   return i - 1;
404 }
405
406 /*
407   Return the size of the argument block needed on the stack to invoke
408   the method MTH.  This may be zero, if all arguments are passed in
409   registers.
410 */
411
412 int
413 method_get_sizeof_arguments (struct objc_method* mth)
414 {
415   const char* type = objc_skip_typespec (mth->method_types);
416   return atoi (type);
417 }
418
419 /*
420   Return a pointer to the next argument of ARGFRAME.  type points to
421   the last argument.  Typical use of this look like:
422
423   {
424     char *datum, *type; 
425     for (datum = method_get_first_argument (method, argframe, &type);
426          datum; datum = method_get_next_argument (argframe, &type))
427       {
428         unsigned flags = objc_get_type_qualifiers (type);
429         type = objc_skip_type_qualifiers (type);
430         if (*type != _C_PTR)
431           [portal encodeData: datum ofType: type];
432         else
433           {
434             if ((flags & _F_IN) == _F_IN)
435               [portal encodeData: *(char**)datum ofType: ++type];
436           }
437       }
438   }
439 */  
440
441 char*
442 method_get_next_argument (arglist_t argframe,
443                           const char **type)
444 {
445   const char *t = objc_skip_argspec (*type);
446
447   if (*t == '\0')
448     return 0;
449
450   *type = t;
451   t = objc_skip_typespec (t);
452
453   if (*t == '+')
454     return argframe->arg_regs + atoi (++t);
455   else
456     return argframe->arg_ptr + atoi (t);
457 }
458
459 /*
460   Return a pointer to the value of the first argument of the method 
461   described in M with the given argumentframe ARGFRAME.  The type
462   is returned in TYPE.  type must be passed to successive calls of 
463   method_get_next_argument.
464 */
465 char*
466 method_get_first_argument (struct objc_method* m,
467                            arglist_t argframe, 
468                            const char** type)
469 {
470   *type = m->method_types;
471   return method_get_next_argument (argframe, type);
472 }
473
474 /*
475    Return a pointer to the ARGth argument of the method
476    M from the frame ARGFRAME.  The type of the argument
477    is returned in the value-result argument TYPE 
478 */
479
480 char*
481 method_get_nth_argument (struct objc_method* m,
482                          arglist_t argframe, int arg, 
483                          const char **type)
484 {
485   const char* t = objc_skip_argspec (m->method_types);
486
487   if (arg > method_get_number_of_arguments (m))
488     return 0;
489
490   while (arg--)
491     t = objc_skip_argspec (t);
492   
493   *type = t;
494   t = objc_skip_typespec (t);
495
496   if (*t == '+')
497     return argframe->arg_regs + atoi (++t);
498   else
499     return argframe->arg_ptr + atoi (t);
500 }
501
502 unsigned
503 objc_get_type_qualifiers (const char* type)
504 {
505   unsigned res = 0;
506   BOOL flag = YES;
507
508   while (flag)
509     switch (*type++)
510       {
511       case _C_CONST:  res |= _F_CONST; break;
512       case _C_IN:     res |= _F_IN; break;
513       case _C_INOUT:  res |= _F_INOUT; break;
514       case _C_OUT:    res |= _F_OUT; break;
515       case _C_BYCOPY: res |= _F_BYCOPY; break;
516       case _C_ONEWAY: res |= _F_ONEWAY; break;
517       default: flag = NO;
518     }
519
520   return res;
521 }