OSDN Git Service

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