/* Encoding of types for Objective C.
- Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1993-2014 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
Bitfield support by Ovidiu Predescu
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+GCC 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)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
-GNU CC is distributed in the hope that it will be useful,
+GCC 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
-/* 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. */
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
-#include "tconfig.h"
-#include "objc-api.h"
-#include "encoding.h"
+/* FIXME: This file has no business including tm.h. */
+
+/* FIXME: This file contains functions that will abort the entire
+ program if they fail. Is that really needed ? */
+#include "objc-private/common.h"
+#include "objc-private/error.h"
+#include "tconfig.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "objc/runtime.h"
+#include "objc-private/module-abi-8.h" /* For struct objc_method */
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h> /* For memcpy. */
+
+#undef MAX
#define MAX(X, Y) \
- ({ typeof(X) __x = (X), __y = (Y); \
+ ({ typeof (X) __x = (X), __y = (Y); \
(__x > __y ? __x : __y); })
+#undef MIN
#define MIN(X, Y) \
- ({ typeof(X) __x = (X), __y = (Y); \
+ ({ typeof (X) __x = (X), __y = (Y); \
(__x < __y ? __x : __y); })
+#undef ROUND
#define ROUND(V, A) \
- ({ typeof(V) __v=(V); typeof(A) __a=(A); \
- __a*((__v+__a-1)/__a); })
+ ({ typeof (V) __v = (V); typeof (A) __a = (A); \
+ __a * ((__v+__a - 1)/__a); })
/* Various hacks for objc_layout_record. These are used by the target
macros. */
-#define TREE_CODE(TYPE) *TYPE
-#define TREE_TYPE(TREE) TREE
+#define TREE_CODE(TYPE) *(TYPE)
+#define TREE_TYPE(TREE) (TREE)
#define RECORD_TYPE _C_STRUCT_B
#define UNION_TYPE _C_UNION_B
#define QUAL_UNION_TYPE _C_UNION_B
#define ARRAY_TYPE _C_ARY_B
-#define TYPE_FIELDS(TYPE) objc_skip_typespec (TYPE)
+#define REAL_TYPE _C_DBL
-#define DECL_MODE(TYPE) *(TYPE)
+#define VECTOR_TYPE _C_VECTOR
+
+#define TYPE_FIELDS(TYPE) ({const char *_field = (TYPE)+1; \
+ while (*_field != _C_STRUCT_E && *_field != _C_STRUCT_B \
+ && *_field != _C_UNION_B && *_field++ != '=') \
+ /* do nothing */; \
+ _field;})
+
+#define DECL_MODE(TYPE) *(TYPE)
+#define TYPE_MODE(TYPE) *(TYPE)
#define DFmode _C_DBL
-#define get_inner_array_type(TYPE) ((TYPE) + 1)
+#define strip_array_types(TYPE) ({const char *_field = (TYPE); \
+ while (*_field == _C_ARY_B)\
+ {\
+ while (isdigit ((unsigned char)*++_field))\
+ ;\
+ }\
+ _field;})
+
+/* Some ports (eg ARM) allow the structure size boundary to be
+ selected at compile-time. We override the normal definition with
+ one that has a constant value for this compilation. */
+#ifndef BITS_PER_UNIT
+#define BITS_PER_UNIT 8
+#endif
+#undef STRUCTURE_SIZE_BOUNDARY
+#define STRUCTURE_SIZE_BOUNDARY (BITS_PER_UNIT * sizeof (struct{char a;}))
+
+/* Some ROUND_TYPE_ALIGN macros use TARGET_foo, and consequently
+ target_flags. Define a dummy entry here to so we don't die.
+ We have to rename it because target_flags may already have been
+ declared extern. */
+#define target_flags not_target_flags
+static int __attribute__ ((__unused__)) not_target_flags = 0;
+
+/* Some ROUND_TYPE_ALIGN use ALTIVEC_VECTOR_MODE (rs6000 darwin).
+ Define a dummy ALTIVEC_VECTOR_MODE so it will not die. */
+#undef ALTIVEC_VECTOR_MODE
+#define ALTIVEC_VECTOR_MODE(MODE) (0)
+
+/* Replace TARGET_VSX, TARGET_ALTIVEC, and TARGET_64BIT with constants based on
+ the current switches, rather than looking in the options structure. */
+#ifdef _ARCH_PPC
+#undef TARGET_VSX
+#undef TARGET_ALTIVEC
+#undef TARGET_64BIT
+
+#ifdef __VSX__
+#define TARGET_VSX 1
+#else
+#define TARGET_VSX 0
+#endif
+#ifdef __ALTIVEC__
+#define TARGET_ALTIVEC 1
+#else
+#define TARGET_ALTIVEC 0
+#endif
-static inline int
-atoi (const char* str)
-{
- int res = 0;
-
- while (isdigit (*str))
- res *= 10, res += (*str++ - '0');
+#ifdef _ARCH_PPC64
+#define TARGET_64BIT 1
+#else
+#define TARGET_64BIT 0
+#endif
+#endif
- return res;
+/* Furthermore, some (powerpc) targets also use TARGET_ALIGN_NATURAL
+ in their alignment macros. Currently[4.5/6], rs6000.h points this
+ to a static variable, initialized by target overrides. This is reset
+ in linux64.h but not in darwin64.h. The macro is not used by *86*. */
+
+#if __MACH__
+# if __LP64__
+# undef TARGET_ALIGN_NATURAL
+# define TARGET_ALIGN_NATURAL 1
+# endif
+
+/* On Darwin32, we need to recurse until we find the starting stuct type. */
+static int
+_darwin_rs6000_special_round_type_align (const char *struc, int comp, int spec)
+{
+ const char *_stp , *_fields = TYPE_FIELDS (struc);
+ if (!_fields)
+ return MAX (comp, spec);
+ _stp = strip_array_types (_fields);
+ if (TYPE_MODE(_stp) == _C_COMPLEX)
+ _stp++;
+ switch (TYPE_MODE(_stp))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ return MAX (MAX (comp, spec), objc_alignof_type (_stp) * BITS_PER_UNIT);
+ break;
+ case DFmode:
+ case _C_LNG_LNG:
+ case _C_ULNG_LNG:
+ return MAX (MAX (comp, spec), 64);
+ break;
+
+ default:
+ return MAX (comp, spec);
+ break;
+ }
}
-/*
- return the size of an object specified by type
-*/
+/* See comment below. */
+#define darwin_rs6000_special_round_type_align(S,C,S2) \
+ (_darwin_rs6000_special_round_type_align ((char*)(S), (int)(C), (int)(S2)))
+#endif
-int
-objc_sizeof_type (const char* type)
+/* FIXME: while this file has no business including tm.h, this
+ definitely has no business defining this macro but it
+ is only way around without really rewritting this file,
+ should look after the branch of 3.4 to fix this. */
+#define rs6000_special_round_type_align(STRUCT, COMPUTED, SPECIFIED) \
+ ({ const char *_fields = TYPE_FIELDS (STRUCT); \
+ ((_fields != 0 \
+ && TYPE_MODE (strip_array_types (TREE_TYPE (_fields))) == DFmode) \
+ ? MAX (MAX (COMPUTED, SPECIFIED), 64) \
+ : MAX (COMPUTED, SPECIFIED));})
+
+#define rs6000_special_adjust_field_align_p(FIELD, COMPUTED) 0
+
+/* Skip a variable name, enclosed in quotes ("). */
+static inline
+const char *
+objc_skip_variable_name (const char *type)
{
- /* Skip the variable name if any */
+ /* Skip the variable name if any. */
if (*type == '"')
{
- for (type++; *type++ != '"';)
- /* do nothing */;
+ /* FIXME: How do we know we won't read beyond the end of the
+ string. Here and in the rest of the file! */
+ /* Skip '"'. */
+ type++;
+ /* Skip to the next '"'. */
+ while (*type != '"')
+ type++;
+ /* Skip '"'. */
+ type++;
}
- switch(*type) {
+ return type;
+}
+
+int
+objc_sizeof_type (const char *type)
+{
+ type = objc_skip_variable_name (type);
+
+ switch (*type) {
+ case _C_BOOL:
+ return sizeof (_Bool);
+ break;
+
case _C_ID:
- return sizeof(id);
+ return sizeof (id);
break;
case _C_CLASS:
- return sizeof(Class);
+ return sizeof (Class);
break;
case _C_SEL:
- return sizeof(SEL);
+ return sizeof (SEL);
break;
case _C_CHR:
- return sizeof(char);
+ return sizeof (char);
break;
-
+
case _C_UCHR:
- return sizeof(unsigned char);
+ return sizeof (unsigned char);
break;
case _C_SHT:
- return sizeof(short);
+ return sizeof (short);
break;
case _C_USHT:
- return sizeof(unsigned short);
+ return sizeof (unsigned short);
break;
case _C_INT:
- return sizeof(int);
+ return sizeof (int);
break;
case _C_UINT:
- return sizeof(unsigned int);
+ return sizeof (unsigned int);
break;
case _C_LNG:
- return sizeof(long);
+ return sizeof (long);
break;
case _C_ULNG:
- return sizeof(unsigned long);
+ return sizeof (unsigned long);
break;
case _C_LNG_LNG:
- return sizeof(long long);
+ return sizeof (long long);
break;
case _C_ULNG_LNG:
- return sizeof(unsigned long long);
+ return sizeof (unsigned long long);
break;
case _C_FLT:
- return sizeof(float);
+ return sizeof (float);
break;
case _C_DBL:
- return sizeof(double);
+ return sizeof (double);
+ break;
+
+ case _C_LNG_DBL:
+ return sizeof (long double);
break;
case _C_VOID:
- return sizeof(void);
+ return sizeof (void);
break;
+
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
- return sizeof(char*);
+ return sizeof (char *);
break;
case _C_ARY_B:
{
- int len = atoi(type+1);
- while (isdigit(*++type));
- return len*objc_aligned_size (type);
+ int len = atoi (type + 1);
+ while (isdigit ((unsigned char)*++type))
+ ;
+ return len * objc_aligned_size (type);
+ }
+ break;
+
+ case _C_VECTOR:
+ {
+ /* Skip the '!'. */
+ type++;
+ /* Skip the '['. */
+ type++;
+
+ /* The size in bytes is the following number. */
+ int size = atoi (type);
+ return size;
}
- break;
+ break;
case _C_BFLD:
{
- /* The new encoding of bitfields is: b 'position' 'type' 'size' */
+ /* The GNU encoding of bitfields is: b 'position' 'type'
+ 'size'. */
int position, size;
int startByte, endByte;
position = atoi (type + 1);
- while (isdigit (*++type));
+ while (isdigit ((unsigned char)*++type))
+ ;
size = atoi (type + 1);
startByte = position / BITS_PER_UNIT;
return endByte - startByte;
}
+ case _C_UNION_B:
case _C_STRUCT_B:
{
struct objc_struct_layout layout;
return size;
}
-
- case _C_UNION_B:
+
+ case _C_COMPLEX:
{
- int max_size = 0;
- while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
- while (*type != _C_UNION_E)
- {
- /* Skip the variable name if any */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
- max_size = MAX (max_size, objc_sizeof_type (type));
- type = objc_skip_typespec (type);
+ type++; /* Skip after the 'j'. */
+ switch (*type)
+ {
+ case _C_CHR:
+ return sizeof (_Complex char);
+ break;
+
+ case _C_UCHR:
+ return sizeof (_Complex unsigned char);
+ break;
+
+ case _C_SHT:
+ return sizeof (_Complex short);
+ break;
+
+ case _C_USHT:
+ return sizeof (_Complex unsigned short);
+ break;
+
+ case _C_INT:
+ return sizeof (_Complex int);
+ break;
+
+ case _C_UINT:
+ return sizeof (_Complex unsigned int);
+ break;
+
+ case _C_LNG:
+ return sizeof (_Complex long);
+ break;
+
+ case _C_ULNG:
+ return sizeof (_Complex unsigned long);
+ break;
+
+ case _C_LNG_LNG:
+ return sizeof (_Complex long long);
+ break;
+
+ case _C_ULNG_LNG:
+ return sizeof (_Complex unsigned long long);
+ break;
+
+ case _C_FLT:
+ return sizeof (_Complex float);
+ break;
+
+ case _C_DBL:
+ return sizeof (_Complex double);
+ break;
+
+ case _C_LNG_DBL:
+ return sizeof (_Complex long double);
+ break;
+
+ default:
+ {
+ /* FIXME: Is this so bad that we have to abort the
+ entire program ? (it applies to all the other
+ _objc_abort calls in this file).
+ */
+ _objc_abort ("unknown complex type %s\n", type);
+ return 0;
+ }
}
- return max_size;
}
-
+
default:
{
- objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
+ _objc_abort ("unknown type %s\n", type);
return 0;
}
}
}
-
-/*
- Return the alignment of an object specified by type
-*/
-
int
-objc_alignof_type(const char* type)
+objc_alignof_type (const char *type)
{
- /* Skip the variable name if any */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
- switch(*type) {
+ type = objc_skip_variable_name (type);
+
+ switch (*type) {
+ case _C_BOOL:
+ return __alignof__ (_Bool);
+ break;
+
case _C_ID:
- return __alignof__(id);
+ return __alignof__ (id);
break;
case _C_CLASS:
- return __alignof__(Class);
+ return __alignof__ (Class);
break;
-
+
case _C_SEL:
- return __alignof__(SEL);
+ return __alignof__ (SEL);
break;
case _C_CHR:
- return __alignof__(char);
+ return __alignof__ (char);
break;
-
+
case _C_UCHR:
- return __alignof__(unsigned char);
+ return __alignof__ (unsigned char);
break;
case _C_SHT:
- return __alignof__(short);
+ return __alignof__ (short);
break;
case _C_USHT:
- return __alignof__(unsigned short);
+ return __alignof__ (unsigned short);
break;
case _C_INT:
- return __alignof__(int);
+ return __alignof__ (int);
break;
case _C_UINT:
- return __alignof__(unsigned int);
+ return __alignof__ (unsigned int);
break;
case _C_LNG:
- return __alignof__(long);
+ return __alignof__ (long);
break;
case _C_ULNG:
- return __alignof__(unsigned long);
+ return __alignof__ (unsigned long);
break;
case _C_LNG_LNG:
- return __alignof__(long long);
+ return __alignof__ (long long);
break;
case _C_ULNG_LNG:
- return __alignof__(unsigned long long);
+ return __alignof__ (unsigned long long);
break;
case _C_FLT:
- return __alignof__(float);
+ return __alignof__ (float);
break;
case _C_DBL:
- return __alignof__(double);
+ return __alignof__ (double);
+ break;
+
+ case _C_LNG_DBL:
+ return __alignof__ (long double);
break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
- return __alignof__(char*);
+ return __alignof__ (char *);
break;
case _C_ARY_B:
- while (isdigit(*++type)) /* do nothing */;
+ while (isdigit ((unsigned char)*++type))
+ /* do nothing */;
return objc_alignof_type (type);
+ case _C_VECTOR:
+ {
+ /* Skip the '!'. */
+ type++;
+ /* Skip the '['. */
+ type++;
+
+ /* Skip the size. */
+ while (isdigit ((unsigned char)*type))
+ type++;
+
+ /* Skip the ','. */
+ type++;
+
+ /* The alignment in bytes is the following number. */
+ return atoi (type);
+ }
case _C_STRUCT_B:
+ case _C_UNION_B:
{
struct objc_struct_layout layout;
unsigned int align;
return align;
}
-
- case _C_UNION_B:
+
+
+ case _C_COMPLEX:
{
- int maxalign = 0;
- while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
- while (*type != _C_UNION_E)
- {
- /* Skip the variable name if any */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
- maxalign = MAX (maxalign, objc_alignof_type (type));
- type = objc_skip_typespec (type);
+ type++; /* Skip after the 'j'. */
+ switch (*type)
+ {
+ case _C_CHR:
+ return __alignof__ (_Complex char);
+ break;
+
+ case _C_UCHR:
+ return __alignof__ (_Complex unsigned char);
+ break;
+
+ case _C_SHT:
+ return __alignof__ (_Complex short);
+ break;
+
+ case _C_USHT:
+ return __alignof__ (_Complex unsigned short);
+ break;
+
+ case _C_INT:
+ return __alignof__ (_Complex int);
+ break;
+
+ case _C_UINT:
+ return __alignof__ (_Complex unsigned int);
+ break;
+
+ case _C_LNG:
+ return __alignof__ (_Complex long);
+ break;
+
+ case _C_ULNG:
+ return __alignof__ (_Complex unsigned long);
+ break;
+
+ case _C_LNG_LNG:
+ return __alignof__ (_Complex long long);
+ break;
+
+ case _C_ULNG_LNG:
+ return __alignof__ (_Complex unsigned long long);
+ break;
+
+ case _C_FLT:
+ return __alignof__ (_Complex float);
+ break;
+
+ case _C_DBL:
+ return __alignof__ (_Complex double);
+ break;
+
+ case _C_LNG_DBL:
+ return __alignof__ (_Complex long double);
+ break;
+
+ default:
+ {
+ _objc_abort ("unknown complex type %s\n", type);
+ return 0;
+ }
}
- return maxalign;
}
default:
{
- objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
+ _objc_abort ("unknown type %s\n", type);
return 0;
}
}
}
-/*
- The aligned size if the size rounded up to the nearest alignment.
-*/
-
int
-objc_aligned_size (const char* type)
+objc_aligned_size (const char *type)
{
int size, align;
- /* Skip the variable name */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
-
+ type = objc_skip_variable_name (type);
size = objc_sizeof_type (type);
align = objc_alignof_type (type);
return ROUND (size, align);
}
-/*
- 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
+objc_promoted_size (const char *type)
{
int size, wordsize;
- /* Skip the variable name */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
-
+ type = objc_skip_variable_name (type);
size = objc_sizeof_type (type);
- wordsize = sizeof (void*);
+ wordsize = sizeof (void *);
return ROUND (size, wordsize);
}
-/*
- Skip type qualifiers. These may eventually precede typespecs
- occurring in method prototype encodings.
-*/
-
-inline const char*
-objc_skip_type_qualifiers (const char* type)
+inline
+const char *
+objc_skip_type_qualifiers (const char *type)
{
while (*type == _C_CONST
- || *type == _C_IN
+ || *type == _C_IN
|| *type == _C_INOUT
- || *type == _C_OUT
+ || *type == _C_OUT
|| *type == _C_BYCOPY
|| *type == _C_BYREF
|| *type == _C_ONEWAY
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)
+inline
+const char *
+objc_skip_typespec (const char *type)
{
- /* Skip the variable name if any */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
-
+ type = objc_skip_variable_name (type);
type = objc_skip_type_qualifiers (type);
-
+
switch (*type) {
case _C_ID:
return type;
else
{
- while (*++type != '"') /* do nothing */;
+ while (*++type != '"')
+ /* do nothing */;
return type + 1;
}
case _C_INT:
case _C_UINT:
case _C_LNG:
+ case _C_BOOL:
case _C_ULNG:
case _C_LNG_LNG:
case _C_ULNG_LNG:
case _C_FLT:
case _C_DBL:
+ case _C_LNG_DBL:
case _C_VOID:
case _C_UNDEF:
return ++type;
break;
+
+ case _C_COMPLEX:
+ return type + 2;
+ break;
case _C_ARY_B:
/* skip digits, typespec and closing ']' */
-
- while(isdigit(*++type));
- type = objc_skip_typespec(type);
+ while (isdigit ((unsigned char)*++type))
+ ;
+ type = objc_skip_typespec (type);
+ if (*type == _C_ARY_E)
+ return ++type;
+ else
+ {
+ _objc_abort ("bad array type %s\n", type);
+ return 0;
+ }
+
+ case _C_VECTOR:
+ /* Skip '!' */
+ type++;
+ /* Skip '[' */
+ type++;
+ /* Skip digits (size) */
+ while (isdigit ((unsigned char)*type))
+ type++;
+ /* Skip ',' */
+ type++;
+ /* Skip digits (alignment) */
+ while (isdigit ((unsigned char)*type))
+ type++;
+ /* Skip typespec. */
+ type = objc_skip_typespec (type);
+ /* Skip closing ']'. */
if (*type == _C_ARY_E)
return ++type;
else
{
- objc_error(nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type);
+ _objc_abort ("bad vector type %s\n", type);
return 0;
}
case _C_BFLD:
- /* The new encoding of bitfields is: b 'position' 'type' 'size' */
- while (isdigit (*++type)); /* skip position */
- while (isdigit (*++type)); /* skip type and size */
+ /* The GNU encoding of bitfields is: b 'position' 'type'
+ 'size'. */
+ while (isdigit ((unsigned char)*++type))
+ ; /* skip position */
+ while (isdigit ((unsigned char)*++type))
+ ; /* skip type and size */
return type;
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); }
+
+ 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); }
+
+ 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:
{
- objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
+ _objc_abort ("unknown type %s\n", type);
return 0;
}
}
}
-/*
- 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)
+inline
+const char *
+objc_skip_offset (const char *type)
{
- if (*type == '+') type++;
- while(isdigit(*++type));
+ /* The offset is prepended by a '+' if the argument is passed in
+ registers. PS: The compiler stopped generating this '+' in
+ version 3.4. */
+ if (*type == '+')
+ type++;
+
+ /* Some people claim that on some platforms, where the stack grows
+ backwards, the compiler generates negative offsets (??). Skip a
+ '-' for such a negative offset. */
+ if (*type == '-')
+ type++;
+
+ /* Skip the digits that represent the offset. */
+ while (isdigit ((unsigned char) *type))
+ type++;
+
return type;
}
-/*
- Skip an argument specification of a method encoding.
-*/
-const char*
-objc_skip_argspec (const char* type)
+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)
+char *
+method_copyReturnType (struct objc_method *method)
{
- int i = 0;
- const char* type = mth->method_types;
- while (*type)
+ if (method == NULL)
+ return 0;
+ else
{
- type = objc_skip_argspec (type);
- i += 1;
- }
- return i - 1;
-}
+ char *returnValue;
+ size_t returnValueSize;
-/*
- 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.
-*/
+ /* Determine returnValueSize. */
+ {
+ /* Find the end of the first argument. We want to return the
+ first argument spec, plus 1 byte for the \0 at the end. */
+ const char *type = method->method_types;
+ if (*type == '\0')
+ return NULL;
+ type = objc_skip_argspec (type);
+ returnValueSize = type - method->method_types + 1;
+ }
-int
-method_get_sizeof_arguments (struct objc_method* mth)
-{
- const char* type = objc_skip_typespec (mth->method_types);
- return atoi (type);
+ /* Copy the first argument into returnValue. */
+ returnValue = malloc (sizeof (char) * returnValueSize);
+ memcpy (returnValue, method->method_types, returnValueSize);
+ returnValue[returnValueSize - 1] = '\0';
+
+ return returnValue;
+ }
}
-/*
- Return a pointer to the next argument of ARGFRAME. type points to
- the last argument. Typical use of this look like:
+char *
+method_copyArgumentType (struct objc_method * method, unsigned int argumentNumber)
+{
+ if (method == NULL)
+ return 0;
+ else
+ {
+ char *returnValue;
+ const char *returnValueStart;
+ size_t returnValueSize;
- {
- char *datum, *type;
- for (datum = method_get_first_argument (method, argframe, &type);
- datum; datum = method_get_next_argument (argframe, &type))
+ /* Determine returnValueStart and returnValueSize. */
{
- unsigned flags = objc_get_type_qualifiers (type);
- type = objc_skip_type_qualifiers (type);
- if (*type != _C_PTR)
- [portal encodeData: datum ofType: type];
- else
+ const char *type = method->method_types;
+
+ /* Skip the first argument (return type). */
+ type = objc_skip_argspec (type);
+
+ /* Now keep skipping arguments until we get to
+ argumentNumber. */
+ while (argumentNumber > 0)
{
- if ((flags & _F_IN) == _F_IN)
- [portal encodeData: *(char**)datum ofType: ++type];
+ /* We are supposed to skip an argument, but the string is
+ finished. This means we were asked for a non-existing
+ argument. */
+ if (*type == '\0')
+ return NULL;
+
+ type = objc_skip_argspec (type);
+ argumentNumber--;
}
+
+ /* If the argument does not exist, return NULL. */
+ if (*type == '\0')
+ return NULL;
+
+ returnValueStart = type;
+ type = objc_skip_argspec (type);
+ returnValueSize = type - returnValueStart + 1;
}
- }
-*/
+
+ /* Copy the argument into returnValue. */
+ returnValue = malloc (sizeof (char) * returnValueSize);
+ memcpy (returnValue, returnValueStart, returnValueSize);
+ returnValue[returnValueSize - 1] = '\0';
-char*
-method_get_next_argument (arglist_t argframe,
- const char **type)
-{
- const char *t = objc_skip_argspec (*type);
+ return returnValue;
+ }
+}
- if (*t == '\0')
- return 0;
+void method_getReturnType (struct objc_method * method, char *returnValue,
+ size_t returnValueSize)
+{
+ if (returnValue == NULL || returnValueSize == 0)
+ return;
- *type = t;
- t = objc_skip_typespec (t);
+ /* Zero the string; we'll then write the argument type at the
+ beginning of it, if needed. */
+ memset (returnValue, 0, returnValueSize);
- if (*t == '+')
- return argframe->arg_regs + atoi (++t);
+ if (method == NULL)
+ return;
else
- return argframe->arg_ptr + atoi (t);
+ {
+ size_t argumentTypeSize;
+
+ /* Determine argumentTypeSize. */
+ {
+ /* Find the end of the first argument. We want to return the
+ first argument spec. */
+ const char *type = method->method_types;
+ if (*type == '\0')
+ return;
+ type = objc_skip_argspec (type);
+ argumentTypeSize = type - method->method_types;
+ if (argumentTypeSize > returnValueSize)
+ argumentTypeSize = returnValueSize;
+ }
+ /* Copy the argument at the beginning of the string. */
+ memcpy (returnValue, method->method_types, argumentTypeSize);
+ }
}
-/*
- 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)
+void method_getArgumentType (struct objc_method * method, unsigned int argumentNumber,
+ char *returnValue, size_t returnValueSize)
{
- *type = m->method_types;
- return method_get_next_argument (argframe, type);
-}
+ if (returnValue == NULL || returnValueSize == 0)
+ return;
-/*
- 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
-*/
+ /* Zero the string; we'll then write the argument type at the
+ beginning of it, if needed. */
+ memset (returnValue, 0, returnValueSize);
-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 (method == NULL)
+ return;
+ else
+ {
+ const char *returnValueStart;
+ size_t argumentTypeSize;
- if (arg > method_get_number_of_arguments (m))
- return 0;
+ /* Determine returnValueStart and argumentTypeSize. */
+ {
+ const char *type = method->method_types;
+
+ /* Skip the first argument (return type). */
+ type = objc_skip_argspec (type);
+
+ /* Now keep skipping arguments until we get to
+ argumentNumber. */
+ while (argumentNumber > 0)
+ {
+ /* We are supposed to skip an argument, but the string is
+ finished. This means we were asked for a non-existing
+ argument. */
+ if (*type == '\0')
+ return;
+
+ type = objc_skip_argspec (type);
+ argumentNumber--;
+ }
+
+ /* If the argument does not exist, it's game over. */
+ if (*type == '\0')
+ return;
- while (arg--)
- t = objc_skip_argspec (t);
-
- *type = t;
- t = objc_skip_typespec (t);
+ returnValueStart = type;
+ type = objc_skip_argspec (type);
+ argumentTypeSize = type - returnValueStart;
+ if (argumentTypeSize > returnValueSize)
+ argumentTypeSize = returnValueSize;
+ }
+ /* Copy the argument at the beginning of the string. */
+ memcpy (returnValue, returnValueStart, argumentTypeSize);
+ }
+}
- if (*t == '+')
- return argframe->arg_regs + atoi (++t);
+unsigned int
+method_getNumberOfArguments (struct objc_method *method)
+{
+ if (method == NULL)
+ return 0;
else
- return argframe->arg_ptr + atoi (t);
+ {
+ unsigned int i = 0;
+ const char *type = method->method_types;
+ while (*type)
+ {
+ type = objc_skip_argspec (type);
+ i += 1;
+ }
+
+ if (i == 0)
+ {
+ /* This could only happen if method_types is invalid; in
+ that case, return 0. */
+ return 0;
+ }
+ else
+ {
+ /* Remove the return type. */
+ return (i - 1);
+ }
+ }
}
unsigned
-objc_get_type_qualifiers (const char* type)
+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_BYREF: res |= _F_BYREF; break;
- case _C_ONEWAY: res |= _F_ONEWAY; break;
+ 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_BYREF: res |= _F_BYREF; break;
+ case _C_ONEWAY: res |= _F_ONEWAY; break;
case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break;
default: flag = NO;
}
return res;
}
-
/* The following three functions can be used to determine how a
structure is laid out by the compiler. For example:
These functions are used by objc_sizeof_type and objc_alignof_type
functions to compute the size and alignment of structures. The
previous method of computing the size and alignment of a structure
- was not working on some architectures, particulary on AIX, and in
- the presence of bitfields inside the structure. */
+ was not working on some architectures, particularly on AIX, and in
+ the presence of bitfields inside the structure. */
void
objc_layout_structure (const char *type,
- struct objc_struct_layout *layout)
+ struct objc_struct_layout *layout)
{
const char *ntype;
- if (*type++ != _C_STRUCT_B)
+ if (*type != _C_UNION_B && *type != _C_STRUCT_B)
{
- objc_error(nil, OBJC_ERR_BAD_TYPE,
- "record type expected in objc_layout_structure, got %s\n",
- type);
+ _objc_abort ("record (or union) type expected in objc_layout_structure, got %s\n",
+ type);
}
+ type ++;
layout->original_type = type;
/* Skip "<name>=" if any. Avoid embedded structures and unions. */
layout->record_size = 0;
layout->record_align = BITS_PER_UNIT;
-#ifdef STRUCTURE_SIZE_BOUNDARY
layout->record_align = MAX (layout->record_align, STRUCTURE_SIZE_BOUNDARY);
-#endif
}
-
BOOL
objc_layout_structure_next_member (struct objc_struct_layout *layout)
{
- register int known_align = layout->record_size;
register int desired_align = 0;
/* The following are used only if the field is a bitfield */
- register const char *bfld_type;
- register int bfld_type_size, bfld_type_align, bfld_field_size;
+ register const char *bfld_type = 0;
+ register int bfld_type_align = 0, bfld_field_size = 0;
/* The current type without the type qualifiers */
const char *type;
-
-#if 1
- if (layout->prev_type == NULL)
- {
- layout->prev_type = layout->type;
- layout->type = objc_skip_typespec (layout->prev_type);
- return YES;
- }
-#endif
+ BOOL unionp = layout->original_type[-1] == _C_UNION_B;
/* Add the size of the previous field to the size of the record. */
if (layout->prev_type)
{
type = objc_skip_type_qualifiers (layout->prev_type);
+ if (unionp)
+ layout->record_size = MAX (layout->record_size,
+ objc_sizeof_type (type) * BITS_PER_UNIT);
- if (*type != _C_BFLD)
+ else if (*type != _C_BFLD)
layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT;
else {
- desired_align = 1;
/* Get the bitfield's type */
for (bfld_type = type + 1;
- isdigit(*bfld_type);
+ isdigit ((unsigned char)*bfld_type);
bfld_type++)
/* do nothing */;
- bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT;
bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT;
bfld_field_size = atoi (objc_skip_typespec (bfld_type));
layout->record_size += bfld_field_size;
}
}
- if (*layout->type == _C_STRUCT_E)
+ if ((unionp && *layout->type == _C_UNION_E)
+ || (!unionp && *layout->type == _C_STRUCT_E))
return NO;
/* Skip the variable name if any */
- if (*layout->type == '"')
- {
- for (layout->type++; *layout->type++ != '"';)
- /* do nothing */;
- }
-
+ layout->type = objc_skip_variable_name (layout->type);
type = objc_skip_type_qualifiers (layout->type);
if (*type != _C_BFLD)
- desired_align = objc_alignof_type(type) * BITS_PER_UNIT;
+ desired_align = objc_alignof_type (type) * BITS_PER_UNIT;
else
{
desired_align = 1;
/* Skip the bitfield's offset */
- for (bfld_type = type + 1; isdigit(*bfld_type); bfld_type++)
+ for (bfld_type = type + 1;
+ isdigit ((unsigned char) *bfld_type);
+ bfld_type++)
/* do nothing */;
- bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT;
bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT;
bfld_field_size = atoi (objc_skip_typespec (bfld_type));
}
+ /* The following won't work for vectors. */
#ifdef BIGGEST_FIELD_ALIGNMENT
desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);
#endif
is meaningless. */
#ifndef PCC_BITFIELD_TYPE_MATTERS
layout->record_align = MAX (layout->record_align, desired_align);
-#else
+#else /* PCC_BITFIELD_TYPE_MATTERS */
if (*type == _C_BFLD)
{
/* For these machines, a zero-length field does not
}
else
layout->record_align = MAX (layout->record_align, desired_align);
-#endif
+#endif /* PCC_BITFIELD_TYPE_MATTERS */
/* Does this field automatically have alignment it needs
by virtue of the fields that precede it and the record's
Bump the cumulative size to multiple of field alignment. */
layout->record_size = ROUND (layout->record_size, desired_align);
}
-
+
/* Jump to the next field in record. */
layout->prev_type = layout->type;
return YES;
}
-
void objc_layout_finish_structure (struct objc_struct_layout *layout,
unsigned int *size,
unsigned int *align)
{
- if (layout->type && *layout->type == _C_STRUCT_E)
+ BOOL unionp = layout->original_type[-1] == _C_UNION_B;
+ if (layout->type
+ && ((!unionp && *layout->type == _C_STRUCT_E)
+ || (unionp && *layout->type == _C_UNION_E)))
{
/* Work out the alignment of the record as one expression and store
in the record type. Round it up to a multiple of the record's
alignment. */
-
-#if defined(ROUND_TYPE_ALIGN) && !defined(__sparc__)
- layout->record_align = ROUND_TYPE_ALIGN (layout->original_type,
+#if defined (ROUND_TYPE_ALIGN) && ! defined (__sparc__)
+ layout->record_align = ROUND_TYPE_ALIGN (layout->original_type-1,
1,
layout->record_align);
#else
*align = layout->record_align / BITS_PER_UNIT;
}
-
void objc_layout_structure_get_info (struct objc_struct_layout *layout,
unsigned int *offset,
unsigned int *align,