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);