/* Encoding of types for Objective C.
- Copyright (C) 1993, 1995, 1996, 1997, 1998, 2000, 2002, 2004, 2009
+ Copyright (C) 1993, 1995, 1996, 1997, 1998, 2000, 2002, 2004, 2009, 2010
Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
Bitfield support by Ovidiu Predescu
/* 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 ?
-*/
+ program if they fail. Is that really needed ? */
#include "objc-private/common.h"
#include "objc-private/error.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) \
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__ && __LP64__
-# undef TARGET_ALIGN_NATURAL
-# define TARGET_ALIGN_NATURAL 1
+#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;
+ }
+}
+
+/* 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
/* 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.
- FIXME1: It's also out of date, darwin no longer has the same alignment
- 'special' as aix - this is probably the origin of the m32 breakage. */
+ 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));})
-/* FIXME: The word 'fixme' is insufficient to explain the wrong-ness
- of this next macro definition. */
-#define darwin_rs6000_special_round_type_align(S,C,S2) \
- rs6000_special_round_type_align(S,C,S2)
-/*
- return the size of an object specified by type
-*/
-int
-objc_sizeof_type (const char *type)
+/* 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 == '"')
{
/* FIXME: How do we know we won't read beyond the end of the
string. Here and in the rest of the file! */
- for (type++; *type++ != '"';)
- /* do nothing */;
+ /* Skip '"'. */
+ type++;
+ /* Skip to the next '"'. */
+ while (*type != '"')
+ type++;
+ /* Skip '"'. */
+ type++;
}
+ return type;
+}
+
+int
+objc_sizeof_type (const char *type)
+{
+ type = objc_skip_variable_name (type);
+
switch (*type) {
case _C_BOOL:
return sizeof (_Bool);
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;
}
}
-
-/*
- Return the alignment of an object specified by type
-*/
-
int
objc_alignof_type (const char *type)
{
- /* Skip the variable name if any */
- if (*type == '"')
- {
- for (type++; *type++ != '"';)
- /* do nothing */;
- }
+ type = objc_skip_variable_name (type);
+
switch (*type) {
case _C_BOOL:
return __alignof__ (_Bool);
}
}
-/*
- The aligned size if the size rounded up to the nearest alignment.
-*/
-
int
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 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 *);
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)
{
return type;
}
-
-/*
- Skip one typespec element. If the typespec is prepended by type
- qualifiers, these are skipped as well.
-*/
-
+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_BFLD:
- /* The new encoding of bitfields is: b 'position' 'type' 'size' */
+ /* The GNU encoding of bitfields is: b 'position' 'type'
+ 'size'. */
while (isdigit ((unsigned char)*++type))
; /* skip position */
while (isdigit ((unsigned char)*++type))
}
}
-/*
- Skip an offset as part of a method encoding. This is prepended by a
- '+' if the argument is passed in registers.
-
- FIXME: The compiler never generates '+'.
-*/
+inline
const char *
objc_skip_offset (const char *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++;
- while (isdigit ((unsigned char) *++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)
{
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;
+ char *returnValue;
+ size_t returnValueSize;
+
+ /* 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;
+ }
+
+ /* Copy the first argument into returnValue. */
+ returnValue = malloc (sizeof (char) * returnValueSize);
+ memcpy (returnValue, method->method_types, returnValueSize);
+ returnValue[returnValueSize - 1] = '\0';
+
+ return returnValue;
}
- 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.
-*/
+char *
+method_copyArgumentType (struct objc_method * method, unsigned int argumentNumber)
+{
+ if (method == NULL)
+ return 0;
+ else
+ {
+ char *returnValue;
+ const char *returnValueStart;
+ size_t returnValueSize;
+
+ /* Determine returnValueStart and returnValueSize. */
+ {
+ 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 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';
+
+ return returnValue;
+ }
+}
+
+void method_getReturnType (struct objc_method * method, char *returnValue,
+ size_t returnValueSize)
+{
+ if (returnValue == NULL || returnValueSize == 0)
+ return;
+
+ /* Zero the string; we'll then write the argument type at the
+ beginning of it, if needed. */
+ memset (returnValue, 0, returnValueSize);
+
+ if (method == NULL)
+ return;
+ else
+ {
+ 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);
+ }
+}
+
+void method_getArgumentType (struct objc_method * method, unsigned int argumentNumber,
+ char *returnValue, size_t returnValueSize)
+{
+ if (returnValue == NULL || returnValueSize == 0)
+ return;
+
+ /* Zero the string; we'll then write the argument type at the
+ beginning of it, if needed. */
+ memset (returnValue, 0, returnValueSize);
+
+ if (method == NULL)
+ return;
+ else
+ {
+ const char *returnValueStart;
+ size_t argumentTypeSize;
+
+ /* 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;
+
+ 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);
+ }
+}
+
+unsigned int
+method_getNumberOfArguments (struct objc_method *method)
+{
+ if (method == NULL)
+ return 0;
+ else
+ {
+ 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);
+ }
+ }
+}
int
+method_get_number_of_arguments (struct objc_method *mth)
+{
+ return method_getNumberOfArguments (mth);
+}
+
+/* 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);
}
}
*/
-
char *
method_get_next_argument (arglist_t argframe, const char **type)
{
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.
-*/
+/* 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,
return method_get_next_argument (argframe, type);
}
-/*
- Return a pointer to the ARGth argument of the method
+/* 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
-*/
-
+ is returned in the value-result argument TYPE. */
char *
method_get_nth_argument (struct objc_method *m,
arglist_t argframe, int arg,
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:
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. */
+ the presence of bitfields inside the structure. */
void
objc_layout_structure (const char *type,
struct objc_struct_layout *layout)
layout->record_align = MAX (layout->record_align, STRUCTURE_SIZE_BOUNDARY);
}
-
BOOL
objc_layout_structure_next_member (struct objc_struct_layout *layout)
{
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)
return YES;
}
-
void objc_layout_finish_structure (struct objc_struct_layout *layout,
unsigned int *size,
unsigned int *align)
*align = layout->record_align / BITS_PER_UNIT;
}
-
void objc_layout_structure_get_info (struct objc_struct_layout *layout,
unsigned int *offset,
unsigned int *align,