]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-typeencoding.m
objc4-437.1.tar.gz
[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
31 /***********************************************************************
32 * SubtypeUntil.
33 *
34 * Delegation.
35 **********************************************************************/
36 static int SubtypeUntil (const char * type,
37 char end)
38 {
39 int level = 0;
40 const char * head = type;
41
42 //
43 while (*type)
44 {
45 if (!*type || (!level && (*type == end)))
46 return (int)(type - head);
47
48 switch (*type)
49 {
50 case ']': case '}': case ')': level--; break;
51 case '[': case '{': case '(': level += 1; break;
52 }
53
54 type += 1;
55 }
56
57 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
58 return 0;
59 }
60
61
62 /***********************************************************************
63 * SkipFirstType.
64 **********************************************************************/
65 static const char * SkipFirstType (const char * type)
66 {
67 while (1)
68 {
69 switch (*type++)
70 {
71 case 'O': /* bycopy */
72 case 'n': /* in */
73 case 'o': /* out */
74 case 'N': /* inout */
75 case 'r': /* const */
76 case 'V': /* oneway */
77 case '^': /* pointers */
78 break;
79
80 /* arrays */
81 case '[':
82 while ((*type >= '0') && (*type <= '9'))
83 type += 1;
84 return type + SubtypeUntil (type, ']') + 1;
85
86 /* structures */
87 case '{':
88 return type + SubtypeUntil (type, '}') + 1;
89
90 /* unions */
91 case '(':
92 return type + SubtypeUntil (type, ')') + 1;
93
94 /* basic types */
95 default:
96 return type;
97 }
98 }
99 }
100
101
102 /***********************************************************************
103 * encoding_getNumberOfArguments.
104 **********************************************************************/
105 __private_extern__ unsigned int
106 encoding_getNumberOfArguments(const char *typedesc)
107 {
108 unsigned nargs;
109
110 // First, skip the return type
111 typedesc = SkipFirstType (typedesc);
112
113 // Next, skip stack size
114 while ((*typedesc >= '0') && (*typedesc <= '9'))
115 typedesc += 1;
116
117 // Now, we have the arguments - count how many
118 nargs = 0;
119 while (*typedesc)
120 {
121 // Traverse argument type
122 typedesc = SkipFirstType (typedesc);
123
124 // Skip GNU runtime's register parameter hint
125 if (*typedesc == '+') typedesc++;
126
127 // Traverse (possibly negative) argument offset
128 if (*typedesc == '-')
129 typedesc += 1;
130 while ((*typedesc >= '0') && (*typedesc <= '9'))
131 typedesc += 1;
132
133 // Made it past an argument
134 nargs += 1;
135 }
136
137 return nargs;
138 }
139
140 /***********************************************************************
141 * encoding_getSizeOfArguments.
142 **********************************************************************/
143 __private_extern__ unsigned
144 encoding_getSizeOfArguments(const char *typedesc)
145 {
146 unsigned stack_size;
147 #if defined(__ppc__) || defined(ppc)
148 unsigned trueBaseOffset;
149 unsigned foundBaseOffset;
150 #endif
151
152 // Get our starting points
153 stack_size = 0;
154
155 // Skip the return type
156 #if defined (__ppc__) || defined(ppc)
157 // Struct returns cause the parameters to be bumped
158 // by a register, so the offset to the receiver is
159 // 4 instead of the normal 0.
160 trueBaseOffset = (*typedesc == '{') ? (unsigned)sizeof(void *) : 0;
161 #endif
162 typedesc = SkipFirstType (typedesc);
163
164 // Convert ASCII number string to integer
165 while ((*typedesc >= '0') && (*typedesc <= '9'))
166 stack_size = (stack_size * 10) + (*typedesc++ - '0');
167 #if defined (__ppc__) || defined(ppc)
168 // NOTE: This is a temporary measure pending a compiler fix.
169 // Work around PowerPC compiler bug wherein the method argument
170 // string contains an incorrect value for the "stack size."
171 // Generally, the size is reported 4 bytes too small, so we apply
172 // that fudge factor. Unfortunately, there is at least one case
173 // where the error is something other than -4: when the last
174 // parameter is a double, the reported stack is much too high
175 // (about 32 bytes). We do not attempt to detect that case.
176 // The result of returning a too-high value is that objc_msgSendv
177 // can bus error if the destination of the marg_list copying
178 // butts up against excluded memory.
179 // This fix disables itself when it sees a correctly built
180 // type string (i.e. the offset for the Id is correct). This
181 // keeps us out of lockstep with the compiler.
182
183 // skip the '@' marking the Id field
184 typedesc = SkipFirstType (typedesc);
185
186 // Skip GNU runtime's register parameter hint
187 if (*typedesc == '+') typedesc++;
188
189 // pick up the offset for the Id field
190 foundBaseOffset = 0;
191 while ((*typedesc >= '0') && (*typedesc <= '9'))
192 foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
193
194 // add fudge factor iff the Id field offset was wrong
195 if (foundBaseOffset != trueBaseOffset)
196 stack_size += 4;
197 #endif
198
199 return stack_size;
200 }
201
202
203 /***********************************************************************
204 * encoding_getArgumentInfo.
205 **********************************************************************/
206 __private_extern__ unsigned int
207 encoding_getArgumentInfo(const char *typedesc, int arg,
208 const char **type, int *offset)
209 {
210 unsigned nargs = 0;
211 int self_offset = 0;
212 BOOL offset_is_negative = NO;
213
214 // First, skip the return type
215 typedesc = SkipFirstType (typedesc);
216
217 // Next, skip stack size
218 while ((*typedesc >= '0') && (*typedesc <= '9'))
219 typedesc += 1;
220
221 // Now, we have the arguments - position typedesc to the appropriate argument
222 while (*typedesc && nargs != arg)
223 {
224
225 // Skip argument type
226 typedesc = SkipFirstType (typedesc);
227
228 if (nargs == 0)
229 {
230 // Skip GNU runtime's register parameter hint
231 if (*typedesc == '+') typedesc++;
232
233 // Skip negative sign in offset
234 if (*typedesc == '-')
235 {
236 offset_is_negative = YES;
237 typedesc += 1;
238 }
239 else
240 offset_is_negative = NO;
241
242 while ((*typedesc >= '0') && (*typedesc <= '9'))
243 self_offset = self_offset * 10 + (*typedesc++ - '0');
244 if (offset_is_negative)
245 self_offset = -(self_offset);
246
247 }
248
249 else
250 {
251 // Skip GNU runtime's register parameter hint
252 if (*typedesc == '+') typedesc++;
253
254 // Skip (possibly negative) argument offset
255 if (*typedesc == '-')
256 typedesc += 1;
257 while ((*typedesc >= '0') && (*typedesc <= '9'))
258 typedesc += 1;
259 }
260
261 nargs += 1;
262 }
263
264 if (*typedesc)
265 {
266 int arg_offset = 0;
267
268 *type = typedesc;
269 typedesc = SkipFirstType (typedesc);
270
271 if (arg == 0)
272 {
273 *offset = 0;
274 }
275
276 else
277 {
278 // Skip GNU register parameter hint
279 if (*typedesc == '+') typedesc++;
280
281 // Pick up (possibly negative) argument offset
282 if (*typedesc == '-')
283 {
284 offset_is_negative = YES;
285 typedesc += 1;
286 }
287 else
288 offset_is_negative = NO;
289
290 while ((*typedesc >= '0') && (*typedesc <= '9'))
291 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
292 if (offset_is_negative)
293 arg_offset = - arg_offset;
294
295 *offset = arg_offset - self_offset;
296 }
297
298 }
299
300 else
301 {
302 *type = 0;
303 *offset = 0;
304 }
305
306 return nargs;
307 }
308
309
310 __private_extern__ void
311 encoding_getReturnType(const char *t, char *dst, size_t dst_len)
312 {
313 size_t len;
314 const char *end;
315
316 if (!dst) return;
317 if (!t) {
318 strncpy(dst, "", dst_len);
319 return;
320 }
321
322 end = SkipFirstType(t);
323 len = end - t;
324 strncpy(dst, t, MIN(len, dst_len));
325 if (len < dst_len) memset(dst+len, 0, dst_len - len);
326 }
327
328 /***********************************************************************
329 * encoding_copyReturnType. Returns the method's return type string
330 * on the heap.
331 **********************************************************************/
332 __private_extern__ char *
333 encoding_copyReturnType(const char *t)
334 {
335 size_t len;
336 const char *end;
337 char *result;
338
339 if (!t) return NULL;
340
341 end = SkipFirstType(t);
342 len = end - t;
343 result = malloc(len + 1);
344 strncpy(result, t, len);
345 result[len] = '\0';
346 return result;
347 }
348
349
350 __private_extern__ void
351 encoding_getArgumentType(const char *t, unsigned int index,
352 char *dst, size_t dst_len)
353 {
354 size_t len;
355 const char *end;
356 int offset;
357
358 if (!dst) return;
359 if (!t) {
360 strncpy(dst, "", dst_len);
361 return;
362 }
363
364 encoding_getArgumentInfo(t, index, &t, &offset);
365
366 if (!t) {
367 strncpy(dst, "", dst_len);
368 return;
369 }
370
371 end = SkipFirstType(t);
372 len = end - t;
373 strncpy(dst, t, MIN(len, dst_len));
374 if (len < dst_len) memset(dst+len, 0, dst_len - len);
375 }
376
377
378 /***********************************************************************
379 * encoding_copyArgumentType. Returns a single argument's type string
380 * on the heap. Argument 0 is `self`; argument 1 is `_cmd`.
381 **********************************************************************/
382 __private_extern__ char *
383 encoding_copyArgumentType(const char *t, unsigned int index)
384 {
385 size_t len;
386 const char *end;
387 char *result;
388 int offset;
389
390 if (!t) return NULL;
391
392 encoding_getArgumentInfo(t, index, &t, &offset);
393
394 if (!t) return NULL;
395
396 end = SkipFirstType(t);
397 len = end - t;
398 result = malloc(len + 1);
399 strncpy(result, t, len);
400 result[len] = '\0';
401 return result;
402 }