summaryrefslogtreecommitdiff
path: root/gcc/objc/encoding.c
diff options
context:
space:
mode:
authorKresten Krab Thorup <krab@gcc.gnu.org>1993-08-24 10:05:25 +0000
committerKresten Krab Thorup <krab@gcc.gnu.org>1993-08-24 10:05:25 +0000
commitb783df230b06493a57c0c66219fdd77db0bdb095 (patch)
treec567aba813f069bff3fb01b3dec742a0571b557a /gcc/objc/encoding.c
parent772fa04a92db00e2aa86f61f5cc3a1e1d9720d52 (diff)
downloadgcc-b783df230b06493a57c0c66219fdd77db0bdb095.tar.gz
Initial revision
From-SVN: r5206
Diffstat (limited to 'gcc/objc/encoding.c')
-rw-r--r--gcc/objc/encoding.c525
1 files changed, 525 insertions, 0 deletions
diff --git a/gcc/objc/encoding.c b/gcc/objc/encoding.c
new file mode 100644
index 00000000000..075d2eee5cd
--- /dev/null
+++ b/gcc/objc/encoding.c
@@ -0,0 +1,525 @@
+/* Encoding of types for Objective C.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#include "encoding.h"
+
+#define MAX(X, Y) \
+ ({ typeof(X) __x = (X), __y = (Y); \
+ (__x > __y ? __x : __y); })
+
+#define MIN(X, Y) \
+ ({ typeof(X) __x = (X), __y = (Y); \
+ (__x < __y ? __x : __y); })
+
+
+static inline int
+atoi (const char* str)
+{
+ int res = 0;
+
+ while (isdigit (*str))
+ res *= 10, res += (*str++ - '0');
+
+ return res;
+}
+
+/*
+ return the size of an object specified by type
+*/
+
+int
+objc_sizeof_type(const char* type)
+{
+ 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_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_STRUCT_B:
+ {
+ int acc_size = 0;
+ int align;
+ while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
+ while (*type != _C_STRUCT_E);
+ {
+ align = objc_alignof_type (type); /* padd to alignment */
+ if ((acc_size % align) != 0)
+ acc_size += align - (acc_size % align);
+ acc_size += objc_sizeof_type (type); /* add component size */
+ type = objc_skip_typespec (type); /* skip component */
+ }
+ return acc_size;
+ }
+
+ case _C_UNION_B:
+ {
+ int max_size = 0;
+ while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
+ while (*type != _C_UNION_E)
+ {
+ max_size = MAX (max_size, objc_sizeof_type (type));
+ type = objc_skip_typespec (type);
+ }
+ return max_size;
+ }
+
+ default:
+ abort();
+ }
+}
+
+
+/*
+ Return the alignment of an object specified by type
+*/
+
+int
+objc_alignof_type(const char* type)
+{
+ 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_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 { int x; double y; } fooalign;
+ while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */;
+ if (*type != _C_STRUCT_E)
+ return MAX (objc_alignof_type (type), __alignof__ (fooalign));
+ else
+ return __alignof__ (fooalign);
+ }
+
+ case _C_UNION_B:
+ {
+ int maxalign = 0;
+ while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
+ while (*type != _C_UNION_E)
+ {
+ maxalign = MAX (maxalign, objc_alignof_type (type));
+ type = objc_skip_typespec (type);
+ }
+ return maxalign;
+ }
+
+ default:
+ abort();
+ }
+}
+
+/*
+ The aligned size if the size rounded up to the nearest alignment.
+*/
+
+int
+objc_aligned_size (const char* type)
+{
+ int size = objc_sizeof_type (type);
+ int align = objc_alignof_type (type);
+
+ if ((size % align) != 0)
+ return size + align - (size % align);
+ else
+ return size;
+}
+
+/*
+ The size rounded up to the nearest integral of the wordsize, taken
+ to be the size of a void*.
+*/
+
+int
+objc_promoted_size (const char* type)
+{
+ int size = objc_sizeof_type (type);
+ int wordsize = sizeof (void*);
+
+ if ((size % wordsize) != 0)
+ return size + wordsize - (size % wordsize);
+ else
+ return size;
+}
+
+/*
+ Skip type qualifiers. These may eventually precede typespecs
+ occuring in method prototype encodings.
+*/
+
+inline const char*
+objc_skip_type_qualifiers (const char* type)
+{
+ while (*type == _C_CONST
+ || *type == _C_IN
+ || *type == _C_INOUT
+ || *type == _C_OUT
+ || *type == _C_BYCOPY
+ || *type == _C_ONEWAY)
+ {
+ type += 1;
+ }
+ return type;
+}
+
+
+/*
+ Skip one typespec element. If the typespec is prepended by type
+ qualifiers, these are skipped as well.
+*/
+
+const char*
+objc_skip_typespec (const char* 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_ULNG:
+ case _C_FLT:
+ case _C_DBL:
+ case _C_VOID:
+ 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
+ abort();
+
+ 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:
+ abort();
+ }
+}
+
+/*
+ Skip an offset as part of a method encoding. This is prepended by a
+ '+' if the argument is passed in registers.
+*/
+inline const char*
+objc_skip_offset (const char* type)
+{
+ if (*type == '+') type++;
+ while(isdigit(*++type));
+ return type;
+}
+
+/*
+ Skip an argument specification of a method encoding.
+*/
+const char*
+objc_skip_argspec (const char* type)
+{
+ type = objc_skip_typespec (type);
+ type = objc_skip_offset (type);
+ return type;
+}
+
+/*
+ Return the number of arguments that the method MTH expects.
+ Note that all methods need two implicit arguments `self' and
+ `_cmd'.
+*/
+int
+method_get_number_of_arguments (struct objc_method* mth)
+{
+ int i = 0;
+ const char* type = mth->method_types;
+ while (*type)
+ {
+ type = objc_skip_argspec (type);
+ i += 1;
+ }
+ return i - 1;
+}
+
+/*
+ Return the size of the argument block needed on the stack to invoke
+ the method MTH. This may be zero, if all arguments are passed in
+ registers.
+*/
+
+int
+method_get_sizeof_arguments (struct objc_method* mth)
+{
+ const char* type = objc_skip_typespec (mth->method_types);
+ return atoi (type);
+}
+
+/*
+ Return a pointer to the next argument of ARGFRAME. type points to
+ the last argument. Typical use of this look like:
+
+ {
+ char *datum, *type;
+ for (datum = method_get_first_argument (method, argframe, &type);
+ datum; datum = method_get_next_argument (argframe, &type))
+ {
+ unsigned flags = objc_get_type_qualifiers (type);
+ type = objc_skip_type_qualifiers (type);
+ if (*type != _C_PTR)
+ [portal encodeData: datum ofType: type];
+ else
+ {
+ if ((flags & _F_IN) == _F_IN)
+ [portal encodeData: *(char**)datum ofType: ++type];
+ }
+ }
+ }
+*/
+
+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);
+}
+
+/*
+ Return a pointer to the value of the first argument of the method
+ described in M with the given argumentframe ARGFRAME. The type
+ is returned in TYPE. type must be passed to successive calls of
+ method_get_next_argument.
+*/
+char*
+method_get_first_argument (struct objc_method* m,
+ arglist_t argframe,
+ const char** type)
+{
+ *type = m->method_types;
+ return method_get_next_argument (argframe, type);
+}
+
+/*
+ Return a pointer to the ARGth argument of the method
+ M from the frame ARGFRAME. The type of the argument
+ is returned in the value-result argument TYPE
+*/
+
+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);
+}
+
+unsigned
+objc_get_type_qualifiers (const char* type)
+{
+ unsigned res = 0;
+ BOOL flag = YES;
+
+ while (flag)
+ switch (*type++)
+ {
+ case _C_CONST: res |= _F_CONST; break;
+ case _C_IN: res |= _F_IN; break;
+ case _C_INOUT: res |= _F_INOUT; break;
+ case _C_OUT: res |= _F_OUT; break;
+ case _C_BYCOPY: res |= _F_BYCOPY; break;
+ case _C_ONEWAY: res |= _F_ONEWAY; break;
+ default: flag = NO;
+ }
+
+ return res;
+}