]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-typeencoding.m
d3b720e9f37883c8b3ce47cf7c776b10252ecb98
[apple/objc4.git] / runtime / objc-typeencoding.m
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /***********************************************************************
25 * objc-typeencoding.m
26 * Parsing of old-style type strings.
27 **********************************************************************/
28
29 #include "objc-private.h"
30 #include <sys/param.h>
31
32 /***********************************************************************
33 * SubtypeUntil.
34 *
35 * Delegation.
36 **********************************************************************/
37 static int SubtypeUntil (const char * type,
38 char end)
39 {
40 int level = 0;
41 const char * head = type;
42
43 //
44 while (*type)
45 {
46 if (!*type || (!level && (*type == end)))
47 return (int)(type - head);
48
49 switch (*type)
50 {
51 case ']': case '}': case ')': level--; break;
52 case '[': case '{': case '(': level += 1; break;
53 }
54
55 type += 1;
56 }
57
58 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
59 return 0;
60 }
61
62
63 /***********************************************************************
64 * SkipFirstType.
65 **********************************************************************/
66 static const char * SkipFirstType (const char * type)
67 {
68 while (1)
69 {
70 switch (*type++)
71 {
72 case 'O': /* bycopy */
73 case 'n': /* in */
74 case 'o': /* out */
75 case 'N': /* inout */
76 case 'r': /* const */
77 case 'V': /* oneway */
78 case '^': /* pointers */
79 break;
80
81 /* arrays */
82 case '[':
83 while ((*type >= '0') && (*type <= '9'))
84 type += 1;
85 return type + SubtypeUntil (type, ']') + 1;
86
87 /* structures */
88 case '{':
89 return type + SubtypeUntil (type, '}') + 1;
90
91 /* unions */
92 case '(':
93 return type + SubtypeUntil (type, ')') + 1;
94
95 /* basic types */
96 default:
97 return type;
98 }
99 }
100 }
101
102
103 /***********************************************************************
104 * encoding_getNumberOfArguments.
105 **********************************************************************/
106 __private_extern__ unsigned int
107 encoding_getNumberOfArguments(const char *typedesc)
108 {
109 unsigned nargs;
110
111 // First, skip the return type
112 typedesc = SkipFirstType (typedesc);
113
114 // Next, skip stack size
115 while ((*typedesc >= '0') && (*typedesc <= '9'))
116 typedesc += 1;
117
118 // Now, we have the arguments - count how many
119 nargs = 0;
120 while (*typedesc)
121 {
122 // Traverse argument type
123 typedesc = SkipFirstType (typedesc);
124
125 // Skip GNU runtime's register parameter hint
126 if (*typedesc == '+') typedesc++;
127
128 // Traverse (possibly negative) argument offset
129 if (*typedesc == '-')
130 typedesc += 1;
131 while ((*typedesc >= '0') && (*typedesc <= '9'))
132 typedesc += 1;
133
134 // Made it past an argument
135 nargs += 1;
136 }
137
138 return nargs;
139 }
140
141 /***********************************************************************
142 * encoding_getSizeOfArguments.
143 **********************************************************************/
144 __private_extern__ unsigned
145 encoding_getSizeOfArguments(const char *typedesc)
146 {
147 unsigned stack_size;
148 #if defined(__ppc__) || defined(ppc)
149 unsigned trueBaseOffset;
150 unsigned foundBaseOffset;
151 #endif
152
153 // Get our starting points
154 stack_size = 0;
155
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;
162 #endif
163 typedesc = SkipFirstType (typedesc);
164
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.
183
184 // skip the '@' marking the Id field
185 typedesc = SkipFirstType (typedesc);
186
187 // Skip GNU runtime's register parameter hint
188 if (*typedesc == '+') typedesc++;
189
190 // pick up the offset for the Id field
191 foundBaseOffset = 0;
192 while ((*typedesc >= '0') && (*typedesc <= '9'))
193 foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
194
195 // add fudge factor iff the Id field offset was wrong
196 if (foundBaseOffset != trueBaseOffset)
197 stack_size += 4;
198 #endif
199
200 return stack_size;
201 }
202
203
204 /***********************************************************************
205 * encoding_getArgumentInfo.
206 **********************************************************************/
207 __private_extern__ unsigned int
208 encoding_getArgumentInfo(const char *typedesc, int arg,
209 const char **type, int *offset)
210 {
211 unsigned nargs = 0;
212 unsigned self_offset = 0;
213 BOOL offset_is_negative = NO;
214
215 // First, skip the return type
216 typedesc = SkipFirstType (typedesc);
217
218 // Next, skip stack size
219 while ((*typedesc >= '0') && (*typedesc <= '9'))
220 typedesc += 1;
221
222 // Now, we have the arguments - position typedesc to the appropriate argument
223 while (*typedesc && nargs != arg)
224 {
225
226 // Skip argument type
227 typedesc = SkipFirstType (typedesc);
228
229 if (nargs == 0)
230 {
231 // Skip GNU runtime's register parameter hint
232 if (*typedesc == '+') typedesc++;
233
234 // Skip negative sign in offset
235 if (*typedesc == '-')
236 {
237 offset_is_negative = YES;
238 typedesc += 1;
239 }
240 else
241 offset_is_negative = NO;
242
243 while ((*typedesc >= '0') && (*typedesc <= '9'))
244 self_offset = self_offset * 10 + (*typedesc++ - '0');
245 if (offset_is_negative)
246 self_offset = -(self_offset);
247
248 }
249
250 else
251 {
252 // Skip GNU runtime's register parameter hint
253 if (*typedesc == '+') typedesc++;
254
255 // Skip (possibly negative) argument offset
256 if (*typedesc == '-')
257 typedesc += 1;
258 while ((*typedesc >= '0') && (*typedesc <= '9'))
259 typedesc += 1;
260 }
261
262 nargs += 1;
263 }
264
265 if (*typedesc)
266 {
267 unsigned arg_offset = 0;
268
269 *type = typedesc;
270 typedesc = SkipFirstType (typedesc);
271
272 if (arg == 0)
273 {
274 *offset = 0;
275 }
276
277 else
278 {
279 // Skip GNU register parameter hint
280 if (*typedesc == '+') typedesc++;
281
282 // Pick up (possibly negative) argument offset
283 if (*typedesc == '-')
284 {
285 offset_is_negative = YES;
286 typedesc += 1;
287 }
288 else
289 offset_is_negative = NO;
290
291 while ((*typedesc >= '0') && (*typedesc <= '9'))
292 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
293 if (offset_is_negative)
294 arg_offset = - arg_offset;
295
296 *offset = arg_offset - self_offset;
297 }
298
299 }
300
301 else
302 {
303 *type = 0;
304 *offset = 0;
305 }
306
307 return nargs;
308 }
309
310
311 __private_extern__ void
312 encoding_getReturnType(const char *t, char *dst, size_t dst_len)
313 {
314 size_t len;
315 const char *end;
316
317 if (!dst) return;
318 if (!t) {
319 strncpy(dst, "", dst_len);
320 return;
321 }
322
323 end = SkipFirstType(t);
324 len = end - t;
325 strncpy(dst, t, MIN(len, dst_len));
326 if (len < dst_len) memset(dst+len, 0, dst_len - len);
327 }
328
329 /***********************************************************************
330 * encoding_copyReturnType. Returns the method's return type string
331 * on the heap.
332 **********************************************************************/
333 __private_extern__ char *
334 encoding_copyReturnType(const char *t)
335 {
336 size_t len;
337 const char *end;
338 char *result;
339
340 if (!t) return NULL;
341
342 end = SkipFirstType(t);
343 len = end - t;
344 result = malloc(len + 1);
345 strncpy(result, t, len);
346 result[len] = '\0';
347 return result;
348 }
349
350
351 __private_extern__ void
352 encoding_getArgumentType(const char *t, unsigned int index,
353 char *dst, size_t dst_len)
354 {
355 size_t len;
356 const char *end;
357 int offset;
358
359 if (!dst) return;
360 if (!t) {
361 strncpy(dst, "", dst_len);
362 return;
363 }
364
365 encoding_getArgumentInfo(t, index, &t, &offset);
366
367 if (!t) {
368 strncpy(dst, "", dst_len);
369 return;
370 }
371
372 end = SkipFirstType(t);
373 len = end - t;
374 strncpy(dst, t, MIN(len, dst_len));
375 if (len < dst_len) memset(dst+len, 0, dst_len - len);
376 }
377
378
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)
385 {
386 size_t len;
387 const char *end;
388 char *result;
389 int offset;
390
391 if (!t) return NULL;
392
393 encoding_getArgumentInfo(t, index, &t, &offset);
394
395 if (!t) return NULL;
396
397 end = SkipFirstType(t);
398 len = end - t;
399 result = malloc(len + 1);
400 strncpy(result, t, len);
401 result[len] = '\0';
402 return result;
403 }