2  * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.
 
   4  * @APPLE_LICENSE_HEADER_START@
 
   6  * This file contains Original Code and/or Modifications of Original Code
 
   7  * as defined in and that are subject to the Apple Public Source License
 
   8  * Version 2.0 (the 'License'). You may not use this file except in
 
   9  * compliance with the License. Please obtain a copy of the License at
 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this
 
  13  * The Original Code and all software distributed under the License are
 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 
  18  * Please see the License for the specific language governing rights and
 
  19  * limitations under the License.
 
  21  * @APPLE_LICENSE_HEADER_END@
 
  24 /***********************************************************************
 
  26 * Parsing of old-style type strings.
 
  27 **********************************************************************/
 
  29 #include "objc-private.h"
 
  30 #include <sys/param.h>
 
  32 /***********************************************************************
 
  36 **********************************************************************/
 
  37 static int      SubtypeUntil           (const char *    type,
 
  41     const char *        head = type;
 
  46         if (!*type || (!level && (*type == end)))
 
  47             return (int)(type - head);
 
  51             case ']': case '}': case ')': level--; break;
 
  52             case '[': case '{': case '(': level += 1; break;
 
  58     _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
 
  63 /***********************************************************************
 
  65 **********************************************************************/
 
  66 static const char *     SkipFirstType      (const char *        type)
 
  72             case 'O':   /* bycopy */
 
  77             case 'V':   /* oneway */
 
  78             case '^':   /* pointers */
 
  83                 while ((*type >= '0') && (*type <= '9'))
 
  85                 return type + SubtypeUntil (type, ']') + 1;
 
  89                 return type + SubtypeUntil (type, '}') + 1;
 
  93                 return type + SubtypeUntil (type, ')') + 1;
 
 103 /***********************************************************************
 
 104 * encoding_getNumberOfArguments.
 
 105 **********************************************************************/
 
 106 __private_extern__ unsigned int 
 
 107 encoding_getNumberOfArguments(const char *typedesc)
 
 111     // First, skip the return type
 
 112     typedesc = SkipFirstType (typedesc);
 
 114     // Next, skip stack size
 
 115     while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 118     // Now, we have the arguments - count how many
 
 122         // Traverse argument type
 
 123         typedesc = SkipFirstType (typedesc);
 
 125         // Skip GNU runtime's register parameter hint
 
 126         if (*typedesc == '+') typedesc++;
 
 128         // Traverse (possibly negative) argument offset
 
 129         if (*typedesc == '-')
 
 131         while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 134         // Made it past an argument
 
 141 /***********************************************************************
 
 142 * encoding_getSizeOfArguments.
 
 143 **********************************************************************/
 
 144 __private_extern__ unsigned 
 
 145 encoding_getSizeOfArguments(const char *typedesc)
 
 148 #if defined(__ppc__) || defined(ppc)
 
 149     unsigned            trueBaseOffset;
 
 150     unsigned            foundBaseOffset;
 
 153     // Get our starting points
 
 156     // Skip the return type
 
 157 #if defined (__ppc__) || defined(ppc)
 
 158     // Struct returns cause the parameters to be bumped
 
 159     // by a register, so the offset to the receiver is
 
 160     // 4 instead of the normal 0.
 
 161     trueBaseOffset = (*typedesc == '{') ? (unsigned)sizeof(void *) : 0;
 
 163     typedesc = SkipFirstType (typedesc);
 
 165     // Convert ASCII number string to integer
 
 166     while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 167         stack_size = (stack_size * 10) + (*typedesc++ - '0');
 
 168 #if defined (__ppc__) || defined(ppc)
 
 169     // NOTE: This is a temporary measure pending a compiler fix.
 
 170     // Work around PowerPC compiler bug wherein the method argument
 
 171     // string contains an incorrect value for the "stack size."
 
 172     // Generally, the size is reported 4 bytes too small, so we apply
 
 173     // that fudge factor.  Unfortunately, there is at least one case
 
 174     // where the error is something other than -4: when the last
 
 175     // parameter is a double, the reported stack is much too high
 
 176     // (about 32 bytes).  We do not attempt to detect that case.
 
 177     // The result of returning a too-high value is that objc_msgSendv
 
 178     // can bus error if the destination of the marg_list copying
 
 179     // butts up against excluded memory.
 
 180     // This fix disables itself when it sees a correctly built
 
 181     // type string (i.e. the offset for the Id is correct).  This
 
 182     // keeps us out of lockstep with the compiler.
 
 184     // skip the '@' marking the Id field
 
 185     typedesc = SkipFirstType (typedesc);
 
 187     // Skip GNU runtime's register parameter hint
 
 188     if (*typedesc == '+') typedesc++;
 
 190     // pick up the offset for the Id field
 
 192     while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 193         foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
 
 195     // add fudge factor iff the Id field offset was wrong
 
 196     if (foundBaseOffset != trueBaseOffset)
 
 204 /***********************************************************************
 
 205 * encoding_getArgumentInfo.
 
 206 **********************************************************************/
 
 207 __private_extern__ unsigned int 
 
 208 encoding_getArgumentInfo(const char *typedesc, int arg,
 
 209                          const char **type, int *offset)
 
 212     unsigned self_offset = 0;
 
 213     BOOL offset_is_negative = NO;
 
 215     // First, skip the return type
 
 216     typedesc = SkipFirstType (typedesc);
 
 218     // Next, skip stack size
 
 219     while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 222     // Now, we have the arguments - position typedesc to the appropriate argument
 
 223     while (*typedesc && nargs != arg)
 
 226         // Skip argument type
 
 227         typedesc = SkipFirstType (typedesc);
 
 231             // Skip GNU runtime's register parameter hint
 
 232             if (*typedesc == '+') typedesc++;
 
 234             // Skip negative sign in offset
 
 235             if (*typedesc == '-')
 
 237                 offset_is_negative = YES;
 
 241                 offset_is_negative = NO;
 
 243             while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 244                 self_offset = self_offset * 10 + (*typedesc++ - '0');
 
 245             if (offset_is_negative)
 
 246                 self_offset = -(self_offset);
 
 252             // Skip GNU runtime's register parameter hint
 
 253             if (*typedesc == '+') typedesc++;
 
 255             // Skip (possibly negative) argument offset
 
 256             if (*typedesc == '-')
 
 258             while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 267         unsigned arg_offset = 0;
 
 270         typedesc = SkipFirstType (typedesc);
 
 279             // Skip GNU register parameter hint
 
 280             if (*typedesc == '+') typedesc++;
 
 282             // Pick up (possibly negative) argument offset
 
 283             if (*typedesc == '-')
 
 285                 offset_is_negative = YES;
 
 289                 offset_is_negative = NO;
 
 291             while ((*typedesc >= '0') && (*typedesc <= '9'))
 
 292                 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
 
 293             if (offset_is_negative)
 
 294                 arg_offset = - arg_offset;
 
 296             *offset = arg_offset - self_offset;
 
 311 __private_extern__ void 
 
 312 encoding_getReturnType(const char *t, char *dst, size_t dst_len)
 
 319         strncpy(dst, "", dst_len);
 
 323     end = SkipFirstType(t);
 
 325     strncpy(dst, t, MIN(len, dst_len));
 
 326     if (len < dst_len) memset(dst+len, 0, dst_len - len);
 
 329 /***********************************************************************
 
 330 * encoding_copyReturnType.  Returns the method's return type string 
 
 332 **********************************************************************/
 
 333 __private_extern__ char *
 
 334 encoding_copyReturnType(const char *t)
 
 342     end = SkipFirstType(t);
 
 344     result = malloc(len + 1);
 
 345     strncpy(result, t, len);
 
 351 __private_extern__ void 
 
 352 encoding_getArgumentType(const char *t, unsigned int index, 
 
 353                          char *dst, size_t dst_len)
 
 361         strncpy(dst, "", dst_len);
 
 365     encoding_getArgumentInfo(t, index, &t, &offset);
 
 368         strncpy(dst, "", dst_len);
 
 372     end = SkipFirstType(t);
 
 374     strncpy(dst, t, MIN(len, dst_len));
 
 375     if (len < dst_len) memset(dst+len, 0, dst_len - len);
 
 379 /***********************************************************************
 
 380 * encoding_copyArgumentType.  Returns a single argument's type string 
 
 381 * on the heap. Argument 0 is `self`; argument 1 is `_cmd`. 
 
 382 **********************************************************************/
 
 383 __private_extern__ char *
 
 384 encoding_copyArgumentType(const char *t, unsigned int index)
 
 393     encoding_getArgumentInfo(t, index, &t, &offset);
 
 397     end = SkipFirstType(t);
 
 399     result = malloc(len + 1);
 
 400     strncpy(result, t, len);