Mercurial > hg > CbC > CbC_gcc
comparison gcc/objc/objc-next-runtime-abi-01.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Next Runtime (ABI-0/1) private. | |
2 Copyright (C) 2011-2017 Free Software Foundation, Inc. | |
3 Contributed by Iain Sandoe (split from objc-act.c) | |
4 | |
5 This file is part of GCC. | |
6 | |
7 GCC is free software; you can redistribute it and/or modify | |
8 it under the terms of the GNU General Public License as published by | |
9 the Free Software Foundation; either version 3, or (at your option) | |
10 any later version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 /* This implements the original NeXT ABI (0) used for m32 code and | |
22 indicated by module version 6. It also implements the small number | |
23 of additions made for properties and optional protocol methods as | |
24 ABI=1 (module version 7). */ | |
25 | |
26 #include "config.h" | |
27 #include "system.h" | |
28 #include "coretypes.h" | |
29 #include "tree.h" | |
30 #include "stringpool.h" | |
31 #include "attribs.h" | |
32 | |
33 #ifdef OBJCPLUS | |
34 #include "cp/cp-tree.h" | |
35 #else | |
36 #include "c/c-tree.h" | |
37 #include "c/c-lang.h" | |
38 #endif | |
39 #include "langhooks.h" | |
40 #include "c-family/c-objc.h" | |
41 #include "objc-act.h" | |
42 | |
43 /* When building Objective-C++, we are not linking against the C | |
44 front-end and so need to replicate the C tree-construction | |
45 functions in some way. */ | |
46 #ifdef OBJCPLUS | |
47 #define OBJCP_REMAP_FUNCTIONS | |
48 #include "objcp-decl.h" | |
49 #endif /* OBJCPLUS */ | |
50 | |
51 #include "target.h" | |
52 #include "c-family/c-target.h" | |
53 #include "tree-iterator.h" | |
54 | |
55 #include "objc-runtime-hooks.h" | |
56 #include "objc-runtime-shared-support.h" | |
57 #include "objc-encoding.h" | |
58 | |
59 /* NeXT ABI 0 and 1 private definitions. */ | |
60 #define DEF_CONSTANT_STRING_CLASS_NAME "NSConstantString" | |
61 | |
62 #define TAG_GETCLASS "objc_getClass" | |
63 #define TAG_GETMETACLASS "objc_getMetaClass" | |
64 | |
65 #define TAG_MSGSEND "objc_msgSend" | |
66 #define TAG_MSGSENDSUPER "objc_msgSendSuper" | |
67 #define TAG_MSGSEND_STRET "objc_msgSend_stret" | |
68 #define TAG_MSGSENDSUPER_STRET "objc_msgSendSuper_stret" | |
69 | |
70 /* NeXT-specific tags. */ | |
71 | |
72 #define TAG_MSGSEND_NONNIL "objc_msgSendNonNil" | |
73 #define TAG_MSGSEND_NONNIL_STRET "objc_msgSendNonNil_stret" | |
74 #define TAG_EXCEPTIONEXTRACT "objc_exception_extract" | |
75 #define TAG_EXCEPTIONTRYENTER "objc_exception_try_enter" | |
76 #define TAG_EXCEPTIONTRYEXIT "objc_exception_try_exit" | |
77 #define TAG_EXCEPTIONMATCH "objc_exception_match" | |
78 #define TAG_SETJMP "_setjmp" | |
79 | |
80 #define TAG_ASSIGNIVAR "objc_assign_ivar" | |
81 #define TAG_ASSIGNGLOBAL "objc_assign_global" | |
82 #define TAG_ASSIGNSTRONGCAST "objc_assign_strongCast" | |
83 | |
84 /* Branch entry points. All that matters here are the addresses; | |
85 functions with these names do not really exist in libobjc. */ | |
86 | |
87 #define TAG_MSGSEND_FAST "objc_msgSend_Fast" | |
88 #define TAG_ASSIGNIVAR_FAST "objc_assign_ivar_Fast" | |
89 | |
90 /* The version identifies which language generation and runtime the | |
91 module (file) was compiled for, and is recorded in the module | |
92 descriptor. */ | |
93 #define OBJC_VERSION (flag_objc_abi >= 1 ? 7 : 6) | |
94 | |
95 #define UTAG_CLASS_EXT "_objc_class_ext" | |
96 #define UTAG_PROPERTY_LIST "_prop_list_t" | |
97 #define UTAG_PROTOCOL_EXT "_objc_protocol_extension" | |
98 | |
99 #define CLS_HAS_CXX_STRUCTORS 0x2000L | |
100 | |
101 /* rt_trees identifiers - shared between NeXT implementations. These | |
102 allow the FE to tag meta-data in a manner that survives LTO and can | |
103 be used when the runtime requires that certain meta-data items | |
104 appear in particular named sections. */ | |
105 | |
106 #include "objc-next-metadata-tags.h" | |
107 extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; | |
108 | |
109 static void next_runtime_01_initialize (void); | |
110 | |
111 static tree next_runtime_abi_01_super_superclassfield_id (void); | |
112 | |
113 static tree next_runtime_abi_01_class_decl (tree); | |
114 static tree next_runtime_abi_01_metaclass_decl (tree); | |
115 static tree next_runtime_abi_01_category_decl (tree); | |
116 static tree next_runtime_abi_01_protocol_decl (tree); | |
117 static tree next_runtime_abi_01_string_decl (tree, const char *, string_section); | |
118 | |
119 static tree next_runtime_abi_01_get_class_reference (tree); | |
120 static tree next_runtime_abi_01_build_selector_reference (location_t, tree, tree); | |
121 static tree next_runtime_abi_01_get_protocol_reference (location_t, tree); | |
122 static tree next_runtime_abi_01_build_ivar_ref (location_t, tree, tree); | |
123 static tree next_runtime_abi_01_get_class_super_ref (location_t, struct imp_entry *, bool); | |
124 static tree next_runtime_abi_01_get_category_super_ref (location_t, struct imp_entry *, bool); | |
125 | |
126 static tree next_runtime_abi_01_receiver_is_class_object (tree); | |
127 static void next_runtime_abi_01_get_arg_type_list_base (vec<tree, va_gc> **, | |
128 tree, int, int); | |
129 static tree next_runtime_abi_01_build_objc_method_call (location_t, tree, tree, | |
130 tree, tree, tree, int); | |
131 static bool next_runtime_abi_01_setup_const_string_class_decl (void); | |
132 static tree next_runtime_abi_01_build_const_string_constructor (location_t, tree, int); | |
133 | |
134 static void objc_generate_v1_next_metadata (void); | |
135 | |
136 static void build_next_objc_exception_stuff (void); | |
137 static tree objc_eh_runtime_type (tree type); | |
138 static tree objc_eh_personality (void); | |
139 static tree build_throw_stmt (location_t, tree, bool); | |
140 static tree objc_build_exc_ptr (struct objc_try_context **); | |
141 static tree begin_catch (struct objc_try_context **, tree, tree, tree, bool); | |
142 static void finish_catch (struct objc_try_context **, tree); | |
143 static tree finish_try_stmt (struct objc_try_context **); | |
144 | |
145 bool | |
146 objc_next_runtime_abi_01_init (objc_runtime_hooks *rthooks) | |
147 { | |
148 if (flag_objc_exceptions | |
149 && !flag_objc_sjlj_exceptions) | |
150 { | |
151 warning_at (UNKNOWN_LOCATION, OPT_Wall, | |
152 "%<-fobjc-sjlj-exceptions%> is the only supported exceptions " | |
153 "system for %<-fnext-runtime%> with %<-fobjc-abi-version%> < 2"); | |
154 } | |
155 | |
156 rthooks->initialize = next_runtime_01_initialize; | |
157 rthooks->default_constant_string_class_name = DEF_CONSTANT_STRING_CLASS_NAME; | |
158 rthooks->tag_getclass = TAG_GETCLASS; | |
159 rthooks->super_superclassfield_ident = next_runtime_abi_01_super_superclassfield_id; | |
160 | |
161 rthooks->class_decl = next_runtime_abi_01_class_decl; | |
162 rthooks->metaclass_decl = next_runtime_abi_01_metaclass_decl; | |
163 rthooks->category_decl = next_runtime_abi_01_category_decl; | |
164 rthooks->protocol_decl = next_runtime_abi_01_protocol_decl; | |
165 rthooks->string_decl = next_runtime_abi_01_string_decl; | |
166 | |
167 rthooks->get_class_reference = next_runtime_abi_01_get_class_reference; | |
168 rthooks->build_selector_reference = next_runtime_abi_01_build_selector_reference; | |
169 rthooks->get_protocol_reference = next_runtime_abi_01_get_protocol_reference; | |
170 rthooks->build_ivar_reference = next_runtime_abi_01_build_ivar_ref; | |
171 rthooks->get_class_super_ref = next_runtime_abi_01_get_class_super_ref; | |
172 rthooks->get_category_super_ref = next_runtime_abi_01_get_category_super_ref; | |
173 | |
174 rthooks->receiver_is_class_object = next_runtime_abi_01_receiver_is_class_object; | |
175 rthooks->get_arg_type_list_base = next_runtime_abi_01_get_arg_type_list_base; | |
176 rthooks->build_objc_method_call = next_runtime_abi_01_build_objc_method_call; | |
177 | |
178 rthooks->setup_const_string_class_decl = | |
179 next_runtime_abi_01_setup_const_string_class_decl; | |
180 rthooks->build_const_string_constructor = | |
181 next_runtime_abi_01_build_const_string_constructor; | |
182 | |
183 rthooks->build_throw_stmt = build_throw_stmt; | |
184 rthooks->build_exc_ptr = objc_build_exc_ptr; | |
185 rthooks->begin_catch = begin_catch; | |
186 rthooks->finish_catch = finish_catch; | |
187 rthooks->finish_try_stmt = finish_try_stmt; | |
188 | |
189 rthooks->generate_metadata = objc_generate_v1_next_metadata; | |
190 return true; | |
191 } | |
192 | |
193 /* We need a way to convey what kind of meta-data are represented by a | |
194 given variable, since each type is expected (by the runtime) to be | |
195 found in a specific named section. The solution must be usable | |
196 with LTO. | |
197 | |
198 The scheme used for NeXT ABI 0/1 (partial matching of variable | |
199 names) is not satisfactory for LTO & ABI-2. We now tag ObjC | |
200 meta-data with identification attributes in the front end. The | |
201 back-end may choose to act on these as it requires. */ | |
202 | |
203 static void | |
204 next_runtime_abi_01_init_metadata_attributes (void) | |
205 { | |
206 if (!objc_meta) | |
207 objc_meta = get_identifier ("OBJC1META"); | |
208 | |
209 if (!meta_base) | |
210 meta_base = get_identifier ("V1_BASE"); | |
211 | |
212 meta_class = get_identifier ("V1_CLAS"); | |
213 meta_metaclass = get_identifier ("V1_META"); | |
214 meta_category = get_identifier ("V1_CATG"); | |
215 meta_protocol = get_identifier ("V1_PROT"); | |
216 | |
217 meta_clac_vars = get_identifier ("V1_CLCV"); | |
218 meta_clai_vars = get_identifier ("V1_CLIV"); | |
219 | |
220 meta_clac_meth = get_identifier ("V1_CLCM"); | |
221 meta_clai_meth = get_identifier ("V1_CLIM"); | |
222 meta_catc_meth = get_identifier ("V1_CACM"); | |
223 meta_cati_meth = get_identifier ("V1_CAIM"); | |
224 meta_proto_cls_meth = get_identifier ("V1_PCLM"); | |
225 meta_proto_nst_meth = get_identifier ("V1_PNSM"); | |
226 | |
227 meta_clas_prot = get_identifier ("V1_CLPR"); | |
228 meta_catg_prot = get_identifier ("V1_CAPR"); | |
229 | |
230 meta_class_reference = get_identifier ("V1_CLRF"); | |
231 meta_proto_ref = get_identifier ("V1_PRFS"); | |
232 meta_sel_refs = get_identifier ("V1_SRFS"); | |
233 | |
234 meta_class_name = get_identifier ("V1_CLSN"); | |
235 meta_meth_name = get_identifier ("V1_METN"); | |
236 meta_meth_type = get_identifier ("V1_METT"); | |
237 meta_prop_name_attr = get_identifier ("V1_STRG"); | |
238 | |
239 meta_modules = get_identifier ("V1_MODU"); | |
240 meta_symtab = get_identifier ("V1_SYMT"); | |
241 meta_info = get_identifier ("V1_INFO"); | |
242 | |
243 meta_proplist = get_identifier ("V1_PLST"); | |
244 meta_protocol_extension = get_identifier ("V1_PEXT"); | |
245 meta_class_extension = get_identifier ("V1_CEXT"); | |
246 | |
247 meta_const_str = get_identifier ("V1_CSTR"); | |
248 } | |
249 | |
250 static void build_v1_class_template (void); | |
251 static void build_v1_category_template (void); | |
252 static void build_v1_protocol_template (void); | |
253 | |
254 static void next_runtime_01_initialize (void) | |
255 { | |
256 tree type; | |
257 | |
258 #ifdef OBJCPLUS | |
259 /* For all NeXT objc ABIs -fobjc-call-cxx-cdtors is on by | |
260 default. */ | |
261 if (!global_options_set.x_flag_objc_call_cxx_cdtors) | |
262 global_options.x_flag_objc_call_cxx_cdtors = 1; | |
263 #endif | |
264 | |
265 /* Set up attributes to be attached to the meta-data so that they | |
266 will be placed in the correct sections. */ | |
267 next_runtime_abi_01_init_metadata_attributes (); | |
268 | |
269 if (flag_objc_abi >= 1) | |
270 objc_prop_list_ptr = build_pointer_type (xref_tag (RECORD_TYPE, | |
271 get_identifier ("_prop_list_t"))); | |
272 | |
273 /* Declare type of selector-objects that represent an operation | |
274 name. */ | |
275 /* `struct objc_selector *' */ | |
276 objc_selector_type = build_pointer_type (xref_tag (RECORD_TYPE, | |
277 get_identifier (TAG_SELECTOR))); | |
278 | |
279 build_v1_class_template (); | |
280 build_super_template (); | |
281 build_v1_protocol_template (); | |
282 build_v1_category_template (); | |
283 | |
284 /* NB: In order to call one of the ..._stret (struct-returning) | |
285 functions, the function *MUST* first be cast to a signature that | |
286 corresponds to the actual ObjC method being invoked. This is | |
287 what is done by the build_objc_method_call() routine below. */ | |
288 | |
289 /* id objc_msgSend (id, SEL, ...); */ | |
290 /* id objc_msgSendNonNil (id, SEL, ...); */ | |
291 /* id objc_msgSend_stret (id, SEL, ...); */ | |
292 /* id objc_msgSendNonNil_stret (id, SEL, ...); */ | |
293 type = build_varargs_function_type_list (objc_object_type, | |
294 objc_object_type, | |
295 objc_selector_type, | |
296 NULL_TREE); | |
297 | |
298 umsg_decl = add_builtin_function (TAG_MSGSEND, | |
299 type, 0, NOT_BUILT_IN, | |
300 NULL, NULL_TREE); | |
301 | |
302 umsg_nonnil_decl = add_builtin_function (TAG_MSGSEND_NONNIL, | |
303 type, 0, NOT_BUILT_IN, | |
304 NULL, NULL_TREE); | |
305 | |
306 umsg_stret_decl = add_builtin_function (TAG_MSGSEND_STRET, | |
307 type, 0, NOT_BUILT_IN, | |
308 NULL, NULL_TREE); | |
309 | |
310 umsg_nonnil_stret_decl = add_builtin_function (TAG_MSGSEND_NONNIL_STRET, | |
311 type, 0, NOT_BUILT_IN, | |
312 NULL, NULL_TREE); | |
313 | |
314 /* These can throw, because the function that gets called can throw | |
315 in Obj-C++, or could itself call something that can throw even in | |
316 Obj-C. */ | |
317 TREE_NOTHROW (umsg_decl) = 0; | |
318 TREE_NOTHROW (umsg_nonnil_decl) = 0; | |
319 TREE_NOTHROW (umsg_stret_decl) = 0; | |
320 TREE_NOTHROW (umsg_nonnil_stret_decl) = 0; | |
321 | |
322 /* id objc_msgSend_Fast (id, SEL, ...) | |
323 __attribute__ ((hard_coded_address (OFFS_MSGSEND_FAST))); */ | |
324 #ifdef OFFS_MSGSEND_FAST | |
325 umsg_fast_decl = add_builtin_function (TAG_MSGSEND_FAST, | |
326 type, 0, NOT_BUILT_IN, | |
327 NULL, NULL_TREE); | |
328 TREE_NOTHROW (umsg_fast_decl) = 0; | |
329 DECL_ATTRIBUTES (umsg_fast_decl) | |
330 = tree_cons (get_identifier ("hard_coded_address"), | |
331 build_int_cst (NULL_TREE, OFFS_MSGSEND_FAST), | |
332 NULL_TREE); | |
333 #else | |
334 /* No direct dispatch available. */ | |
335 umsg_fast_decl = umsg_decl; | |
336 #endif | |
337 | |
338 /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */ | |
339 /* id objc_msgSendSuper_stret (struct objc_super *, SEL, ...); */ | |
340 type = build_varargs_function_type_list (objc_object_type, | |
341 objc_super_type, | |
342 objc_selector_type, | |
343 NULL_TREE); | |
344 umsg_super_decl = add_builtin_function (TAG_MSGSENDSUPER, | |
345 type, 0, NOT_BUILT_IN, | |
346 NULL, NULL_TREE); | |
347 umsg_super_stret_decl = add_builtin_function (TAG_MSGSENDSUPER_STRET, | |
348 type, 0, NOT_BUILT_IN, 0, | |
349 NULL_TREE); | |
350 TREE_NOTHROW (umsg_super_decl) = 0; | |
351 TREE_NOTHROW (umsg_super_stret_decl) = 0; | |
352 | |
353 type = build_function_type_list (objc_object_type, | |
354 const_string_type_node, | |
355 NULL_TREE); | |
356 | |
357 /* id objc_getClass (const char *); */ | |
358 objc_get_class_decl | |
359 = add_builtin_function (TAG_GETCLASS, type, 0, NOT_BUILT_IN, | |
360 NULL, NULL_TREE); | |
361 | |
362 /* id objc_getMetaClass (const char *); */ | |
363 objc_get_meta_class_decl | |
364 = add_builtin_function (TAG_GETMETACLASS, type, 0, NOT_BUILT_IN, NULL, NULL_TREE); | |
365 | |
366 /* This is the type of all of the following functions | |
367 objc_copyStruct(). */ | |
368 type = build_function_type_list (void_type_node, | |
369 ptr_type_node, | |
370 const_ptr_type_node, | |
371 ptrdiff_type_node, | |
372 boolean_type_node, | |
373 boolean_type_node, | |
374 NULL_TREE); | |
375 /* Declare the following function: | |
376 void | |
377 objc_copyStruct (void *destination, const void *source, | |
378 ptrdiff_t size, BOOL is_atomic, BOOL has_strong); */ | |
379 objc_copyStruct_decl = add_builtin_function ("objc_copyStruct", | |
380 type, 0, NOT_BUILT_IN, | |
381 NULL, NULL_TREE); | |
382 TREE_NOTHROW (objc_copyStruct_decl) = 0; | |
383 objc_getPropertyStruct_decl = NULL_TREE; | |
384 objc_setPropertyStruct_decl = NULL_TREE; | |
385 | |
386 build_next_objc_exception_stuff (); | |
387 if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) | |
388 using_eh_for_cleanups (); | |
389 lang_hooks.eh_runtime_type = objc_eh_runtime_type; | |
390 lang_hooks.eh_personality = objc_eh_personality; | |
391 } | |
392 | |
393 /* --- templates --- */ | |
394 | |
395 /* struct _objc_class | |
396 { | |
397 struct _objc_class *isa; | |
398 struct _objc_class *super_class; | |
399 char *name; | |
400 long version; | |
401 long info; | |
402 long instance_size; | |
403 struct _objc_ivar_list *ivars; | |
404 struct _objc_method_list *methods; | |
405 struct objc_cache *cache; | |
406 struct _objc_protocol_list *protocols; | |
407 #if ABI=1 | |
408 const char *ivar_layout; | |
409 struct _objc_class_ext *ext; | |
410 #else | |
411 void *sel_id; | |
412 void *gc_object_type; | |
413 #endif | |
414 }; */ | |
415 | |
416 /* The 'sel_id' & 'gc_object_type' fields are not used by the NeXT | |
417 runtime. We generate them for ABI==0 to maintain backward binary | |
418 compatibility. */ | |
419 | |
420 static void | |
421 build_v1_class_template (void) | |
422 { | |
423 tree ptype, decls, *chain = NULL; | |
424 | |
425 objc_class_template = objc_start_struct (get_identifier (UTAG_CLASS)); | |
426 | |
427 /* struct _objc_class *isa; */ | |
428 decls = add_field_decl (build_pointer_type (objc_class_template), | |
429 "isa", &chain); | |
430 | |
431 /* struct _objc_class *super_class; */ | |
432 add_field_decl (build_pointer_type (objc_class_template), | |
433 "super_class", &chain); | |
434 | |
435 /* char *name; */ | |
436 add_field_decl (string_type_node, "name", &chain); | |
437 | |
438 /* long version; */ | |
439 add_field_decl (long_integer_type_node, "version", &chain); | |
440 | |
441 /* long info; */ | |
442 add_field_decl (long_integer_type_node, "info", &chain); | |
443 | |
444 /* long instance_size; */ | |
445 add_field_decl (long_integer_type_node, "instance_size", &chain); | |
446 | |
447 /* struct _objc_ivar_list *ivars; */ | |
448 add_field_decl (objc_ivar_list_ptr,"ivars", &chain); | |
449 | |
450 /* struct _objc_method_list *methods; */ | |
451 add_field_decl (objc_method_list_ptr, "methods", &chain); | |
452 | |
453 /* struct objc_cache *cache; */ | |
454 ptype = build_pointer_type (xref_tag (RECORD_TYPE, | |
455 get_identifier ("objc_cache"))); | |
456 add_field_decl (ptype, "cache", &chain); | |
457 | |
458 /* struct _objc_protocol **protocol_list; */ | |
459 ptype = build_pointer_type (build_pointer_type | |
460 (xref_tag (RECORD_TYPE, | |
461 get_identifier (UTAG_PROTOCOL)))); | |
462 add_field_decl (ptype, "protocol_list", &chain); | |
463 | |
464 if (flag_objc_abi >= 1) | |
465 { | |
466 /* const char *ivar_layout; */ | |
467 add_field_decl (const_string_type_node, "ivar_layout", &chain); | |
468 | |
469 /* struct _objc_class_ext *ext; */ | |
470 ptype = build_pointer_type (xref_tag (RECORD_TYPE, | |
471 get_identifier (UTAG_CLASS_EXT))); | |
472 add_field_decl (ptype, "ext", &chain); | |
473 } | |
474 else | |
475 { | |
476 /* void *sel_id; */ | |
477 add_field_decl (build_pointer_type (void_type_node), "sel_id", &chain); | |
478 /* void *gc_object_type; */ | |
479 add_field_decl (build_pointer_type (void_type_node), "gc_object_type", | |
480 &chain); | |
481 } | |
482 | |
483 objc_finish_struct (objc_class_template, decls); | |
484 } | |
485 | |
486 /* struct _objc_category | |
487 { | |
488 char *category_name; | |
489 char *class_name; | |
490 struct _objc_method_list *instance_methods; | |
491 struct _objc_method_list *class_methods; | |
492 struct _objc_protocol_list *protocols; | |
493 #if ABI=1 | |
494 uint32_t size; // sizeof (struct _objc_category) | |
495 struct _objc_property_list *instance_properties; // category's own @property decl. | |
496 #endif | |
497 }; */ | |
498 | |
499 static void | |
500 build_v1_category_template (void) | |
501 { | |
502 tree ptype, decls, *chain = NULL; | |
503 | |
504 objc_category_template = objc_start_struct (get_identifier (UTAG_CATEGORY)); | |
505 | |
506 /* char *category_name; */ | |
507 decls = add_field_decl (string_type_node, "category_name", &chain); | |
508 | |
509 /* char *class_name; */ | |
510 add_field_decl (string_type_node, "class_name", &chain); | |
511 | |
512 /* struct _objc_method_list *instance_methods; */ | |
513 add_field_decl (objc_method_list_ptr, "instance_methods", &chain); | |
514 | |
515 /* struct _objc_method_list *class_methods; */ | |
516 add_field_decl (objc_method_list_ptr, "class_methods", &chain); | |
517 | |
518 /* struct _objc_protocol **protocol_list; */ | |
519 ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); | |
520 add_field_decl (ptype, "protocol_list", &chain); | |
521 | |
522 if (flag_objc_abi >= 1) | |
523 { | |
524 add_field_decl (integer_type_node, "size", &chain); | |
525 | |
526 /* struct _objc_property_list *instance_properties; | |
527 This field describes a category's @property declarations. | |
528 Properties from inherited protocols are not included. */ | |
529 ptype = build_pointer_type (xref_tag (RECORD_TYPE, | |
530 get_identifier (UTAG_PROPERTY_LIST))); | |
531 add_field_decl (ptype, "instance_properties", &chain); | |
532 } | |
533 objc_finish_struct (objc_category_template, decls); | |
534 } | |
535 | |
536 /* Begin code generation for protocols... | |
537 Modified for ObjC #1 extensions. */ | |
538 | |
539 /* struct _objc_protocol | |
540 { | |
541 #if ABI=1 | |
542 struct _objc_protocol_extension *isa; | |
543 #else | |
544 struct _objc_class *isa; | |
545 #endif | |
546 | |
547 char *protocol_name; | |
548 struct _objc_protocol **protocol_list; | |
549 struct _objc__method_prototype_list *instance_methods; | |
550 struct _objc__method_prototype_list *class_methods; | |
551 }; */ | |
552 | |
553 static void | |
554 build_v1_protocol_template (void) | |
555 { | |
556 tree ptype, decls, *chain = NULL; | |
557 | |
558 objc_protocol_template = objc_start_struct (get_identifier (UTAG_PROTOCOL)); | |
559 | |
560 if (flag_objc_abi >= 1) | |
561 /* struct _objc_protocol_extension *isa; */ | |
562 ptype = build_pointer_type (xref_tag (RECORD_TYPE, | |
563 get_identifier (UTAG_PROTOCOL_EXT))); | |
564 else | |
565 /* struct _objc_class *isa; */ | |
566 ptype = build_pointer_type (xref_tag (RECORD_TYPE, | |
567 get_identifier (UTAG_CLASS))); | |
568 | |
569 decls = add_field_decl (ptype, "isa", &chain); | |
570 | |
571 /* char *protocol_name; */ | |
572 add_field_decl (string_type_node, "protocol_name", &chain); | |
573 | |
574 /* struct _objc_protocol **protocol_list; */ | |
575 ptype = build_pointer_type (build_pointer_type (objc_protocol_template)); | |
576 add_field_decl (ptype, "protocol_list", &chain); | |
577 | |
578 /* struct _objc__method_prototype_list *instance_methods; */ | |
579 add_field_decl (objc_method_proto_list_ptr, "instance_methods", &chain); | |
580 | |
581 /* struct _objc__method_prototype_list *class_methods; */ | |
582 add_field_decl (objc_method_proto_list_ptr, "class_methods", &chain); | |
583 | |
584 objc_finish_struct (objc_protocol_template, decls); | |
585 } | |
586 | |
587 /* --- names, decls identifiers --- */ | |
588 | |
589 static tree | |
590 next_runtime_abi_01_super_superclassfield_id (void) | |
591 { | |
592 if (!super_superclassfield_id) | |
593 super_superclassfield_id = get_identifier ("super_class"); | |
594 return super_superclassfield_id; | |
595 } | |
596 | |
597 static tree | |
598 next_runtime_abi_01_class_decl (tree klass) | |
599 { | |
600 tree decl; | |
601 char buf[BUFSIZE]; | |
602 snprintf (buf, BUFSIZE, "_OBJC_Class_%s", | |
603 IDENTIFIER_POINTER (CLASS_NAME (klass))); | |
604 decl = start_var_decl (objc_class_template, buf); | |
605 OBJCMETA (decl, objc_meta, meta_class); | |
606 return decl; | |
607 } | |
608 | |
609 static tree | |
610 next_runtime_abi_01_metaclass_decl (tree klass) | |
611 { | |
612 tree decl; | |
613 char buf[BUFSIZE]; | |
614 snprintf (buf, BUFSIZE, "_OBJC_MetaClass_%s", | |
615 IDENTIFIER_POINTER (CLASS_NAME (klass))); | |
616 decl = start_var_decl (objc_class_template, buf); | |
617 OBJCMETA (decl, objc_meta, meta_metaclass); | |
618 return decl; | |
619 } | |
620 | |
621 static tree | |
622 next_runtime_abi_01_category_decl (tree klass) | |
623 { | |
624 tree decl; | |
625 char buf[BUFSIZE]; | |
626 snprintf (buf, BUFSIZE, "_OBJC_Category_%s_on_%s", | |
627 IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass)), | |
628 IDENTIFIER_POINTER (CLASS_NAME (klass))); | |
629 decl = start_var_decl (objc_category_template, buf); | |
630 OBJCMETA (decl, objc_meta, meta_category); | |
631 return decl; | |
632 } | |
633 | |
634 static tree | |
635 next_runtime_abi_01_protocol_decl (tree p) | |
636 { | |
637 tree decl; | |
638 char buf[BUFSIZE]; | |
639 | |
640 /* static struct _objc_protocol _OBJC_Protocol_<mumble>; */ | |
641 | |
642 snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", | |
643 IDENTIFIER_POINTER (PROTOCOL_NAME (p))); | |
644 decl = start_var_decl (objc_protocol_template, buf); | |
645 OBJCMETA (decl, objc_meta, meta_protocol); | |
646 return decl; | |
647 } | |
648 | |
649 static tree | |
650 next_runtime_abi_01_string_decl (tree type, const char *name, string_section where) | |
651 { | |
652 tree var = start_var_decl (type, name); | |
653 switch (where) | |
654 { | |
655 case class_names: | |
656 OBJCMETA (var, objc_meta, meta_class_name); | |
657 break; | |
658 case meth_var_names: | |
659 OBJCMETA (var, objc_meta, meta_meth_name); | |
660 break; | |
661 case meth_var_types: | |
662 OBJCMETA (var, objc_meta, meta_meth_type); | |
663 break; | |
664 case prop_names_attr: | |
665 OBJCMETA (var, objc_meta, meta_prop_name_attr); | |
666 break; | |
667 default: | |
668 OBJCMETA (var, objc_meta, meta_base); | |
669 break; | |
670 } | |
671 return var; | |
672 } | |
673 | |
674 /* --- entry --- */ | |
675 | |
676 static GTY(()) int class_reference_idx; | |
677 | |
678 static tree | |
679 build_class_reference_decl (void) | |
680 { | |
681 tree decl; | |
682 char buf[BUFSIZE]; | |
683 | |
684 sprintf (buf, "_OBJC_ClassRefs_%d", class_reference_idx++); | |
685 decl = start_var_decl (objc_class_type, buf); | |
686 | |
687 return decl; | |
688 } | |
689 | |
690 static tree | |
691 next_runtime_abi_01_get_class_reference (tree ident) | |
692 { | |
693 if (!flag_zero_link) | |
694 { | |
695 tree *chain; | |
696 tree decl; | |
697 | |
698 for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain)) | |
699 if (TREE_VALUE (*chain) == ident) | |
700 { | |
701 if (! TREE_PURPOSE (*chain)) | |
702 TREE_PURPOSE (*chain) = build_class_reference_decl (); | |
703 | |
704 return TREE_PURPOSE (*chain); | |
705 } | |
706 | |
707 decl = build_class_reference_decl (); | |
708 *chain = tree_cons (decl, ident, NULL_TREE); | |
709 return decl; | |
710 } | |
711 else | |
712 { | |
713 tree params; | |
714 | |
715 add_class_reference (ident); | |
716 | |
717 params = build_tree_list (NULL_TREE, | |
718 my_build_string_pointer | |
719 (IDENTIFIER_LENGTH (ident) + 1, | |
720 IDENTIFIER_POINTER (ident))); | |
721 | |
722 return build_function_call (input_location, objc_get_class_decl, params); | |
723 } | |
724 } | |
725 | |
726 /* Used by build_function_type_for_method. Append the types for | |
727 receiver & _cmd at the start of a method argument list to ARGTYPES. | |
728 CONTEXT is either METHOD_DEF or METHOD_REF, saying whether we are | |
729 trying to define a method or call one. SUPERFLAG says this is for a | |
730 send to super. METH may be NULL, in the case that there is no | |
731 prototype. */ | |
732 | |
733 static void | |
734 next_runtime_abi_01_get_arg_type_list_base (vec<tree, va_gc> **argtypes, | |
735 tree meth, int context, | |
736 int superflag) | |
737 { | |
738 tree receiver_type; | |
739 | |
740 if (superflag) | |
741 receiver_type = objc_super_type; | |
742 else if (context == METHOD_DEF && TREE_CODE (meth) == INSTANCE_METHOD_DECL) | |
743 receiver_type = objc_instance_type; | |
744 else | |
745 receiver_type = objc_object_type; | |
746 | |
747 vec_safe_push (*argtypes, receiver_type); | |
748 /* Selector type - will eventually change to `int'. */ | |
749 vec_safe_push (*argtypes, objc_selector_type); | |
750 } | |
751 | |
752 static tree | |
753 next_runtime_abi_01_receiver_is_class_object (tree receiver) | |
754 { | |
755 if (TREE_CODE (receiver) == VAR_DECL | |
756 && IS_CLASS (TREE_TYPE (receiver))) | |
757 { | |
758 /* The receiver is a variable created by build_class_reference_decl. */ | |
759 tree chain = cls_ref_chain ; | |
760 /* Look up the identifier in the relevant chain. */ | |
761 for (; chain; chain = TREE_CHAIN (chain)) | |
762 if (TREE_PURPOSE (chain) == receiver) | |
763 return TREE_VALUE (chain); | |
764 } | |
765 return NULL_TREE; | |
766 } | |
767 | |
768 static tree | |
769 build_selector_reference_decl (tree ident) | |
770 { | |
771 tree decl; | |
772 char *t, buf[BUFSIZE]; | |
773 | |
774 snprintf (buf, BUFSIZE, "_OBJC_SelRef_%s", IDENTIFIER_POINTER (ident)); | |
775 t = buf; | |
776 while (*t) | |
777 { | |
778 if (*t==':') | |
779 *t = '$'; /* Underscore would clash between foo:bar and foo_bar. */ | |
780 t++; | |
781 } | |
782 decl = start_var_decl (objc_selector_type, buf); | |
783 OBJCMETA (decl, objc_meta, meta_sel_refs); | |
784 return decl; | |
785 } | |
786 | |
787 static tree | |
788 next_runtime_abi_01_build_selector_reference (location_t loc ATTRIBUTE_UNUSED, | |
789 tree ident, | |
790 tree proto ATTRIBUTE_UNUSED) | |
791 { | |
792 tree *chain = &sel_ref_chain; | |
793 tree expr; | |
794 | |
795 while (*chain) | |
796 { | |
797 if (TREE_VALUE (*chain) == ident) | |
798 return TREE_PURPOSE (*chain); | |
799 | |
800 chain = &TREE_CHAIN (*chain); | |
801 } | |
802 | |
803 expr = build_selector_reference_decl (ident); | |
804 | |
805 *chain = tree_cons (expr, ident, NULL_TREE); | |
806 | |
807 return expr; | |
808 } | |
809 | |
810 /* Build a tree expression to send OBJECT the operation SELECTOR, | |
811 looking up the method on object LOOKUP_OBJECT (often same as OBJECT), | |
812 assuming the method has prototype METHOD_PROTOTYPE. | |
813 (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.) | |
814 LOC is the location of the expression to build. | |
815 Use METHOD_PARAMS as list of args to pass to the method. | |
816 If SUPER_FLAG is nonzero, we look up the superclass's method. */ | |
817 | |
818 static tree | |
819 build_objc_method_call (location_t loc, int super_flag, tree method_prototype, | |
820 tree lookup_object, tree selector, | |
821 tree method_params) | |
822 { | |
823 tree sender, sender_cast, method, t; | |
824 tree rcv_p = (super_flag ? objc_super_type : objc_object_type); | |
825 vec<tree, va_gc> *parms; | |
826 unsigned nparm = (method_params ? list_length (method_params) : 0); | |
827 | |
828 /* If a prototype for the method to be called exists, then cast | |
829 the sender's return type and arguments to match that of the method. | |
830 Otherwise, leave sender as is. */ | |
831 tree ret_type | |
832 = (method_prototype | |
833 ? TREE_VALUE (TREE_TYPE (method_prototype)) | |
834 : objc_object_type); | |
835 tree ftype = build_function_type_for_method (ret_type, method_prototype, | |
836 METHOD_REF, super_flag); | |
837 | |
838 if (method_prototype && METHOD_TYPE_ATTRIBUTES (method_prototype)) | |
839 ftype = build_type_attribute_variant (ftype, | |
840 METHOD_TYPE_ATTRIBUTES | |
841 (method_prototype)); | |
842 | |
843 sender_cast = build_pointer_type (ftype); | |
844 | |
845 lookup_object = build_c_cast (loc, rcv_p, lookup_object); | |
846 | |
847 /* Use SAVE_EXPR to avoid evaluating the receiver twice. */ | |
848 lookup_object = save_expr (lookup_object); | |
849 | |
850 /* Param list + 2 slots for object and selector. */ | |
851 vec_alloc (parms, nparm + 2); | |
852 | |
853 /* If we are returning a struct in memory, and the address | |
854 of that memory location is passed as a hidden first | |
855 argument, then change which messenger entry point this | |
856 expr will call. NB: Note that sender_cast remains | |
857 unchanged (it already has a struct return type). */ | |
858 if (!targetm.calls.struct_value_rtx (0, 0) | |
859 && (TREE_CODE (ret_type) == RECORD_TYPE | |
860 || TREE_CODE (ret_type) == UNION_TYPE) | |
861 && targetm.calls.return_in_memory (ret_type, 0)) | |
862 sender = (super_flag ? umsg_super_stret_decl | |
863 : flag_nil_receivers ? umsg_stret_decl | |
864 : umsg_nonnil_stret_decl); | |
865 else | |
866 sender = (super_flag ? umsg_super_decl | |
867 : (flag_nil_receivers ? (flag_objc_direct_dispatch | |
868 ? umsg_fast_decl | |
869 : umsg_decl) | |
870 : umsg_nonnil_decl)); | |
871 method = build_fold_addr_expr_loc (loc, sender); | |
872 | |
873 /* Pass the object to the method. */ | |
874 parms->quick_push (lookup_object); | |
875 /* Pass the selector to the method. */ | |
876 parms->quick_push (selector); | |
877 /* Now append the remainder of the parms. */ | |
878 if (nparm) | |
879 for (; method_params; method_params = TREE_CHAIN (method_params)) | |
880 parms->quick_push (TREE_VALUE (method_params)); | |
881 | |
882 /* Build an obj_type_ref, with the correct cast for the method call. */ | |
883 t = build3 (OBJ_TYPE_REF, sender_cast, method, | |
884 lookup_object, size_zero_node); | |
885 t = build_function_call_vec (loc, vNULL, t, parms, NULL); | |
886 vec_free (parms); | |
887 return t; | |
888 } | |
889 | |
890 static tree | |
891 next_runtime_abi_01_build_objc_method_call (location_t loc, | |
892 tree method_prototype, | |
893 tree receiver, | |
894 tree rtype ATTRIBUTE_UNUSED, | |
895 tree sel_name, | |
896 tree method_params, | |
897 int super) | |
898 { | |
899 tree selector = next_runtime_abi_01_build_selector_reference (loc, sel_name, | |
900 NULL_TREE); | |
901 | |
902 return build_objc_method_call (loc, super, method_prototype, | |
903 receiver, selector, method_params); | |
904 } | |
905 | |
906 static tree | |
907 next_runtime_abi_01_get_protocol_reference (location_t loc, tree p) | |
908 { | |
909 tree expr; | |
910 | |
911 if (!PROTOCOL_FORWARD_DECL (p)) | |
912 PROTOCOL_FORWARD_DECL (p) = next_runtime_abi_01_protocol_decl (p); | |
913 | |
914 expr = build_unary_op (loc, ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); | |
915 return convert (objc_protocol_type, expr); | |
916 } | |
917 | |
918 /* For ABI 0/1 and IVAR is just a fixed offset in the class struct. */ | |
919 | |
920 static tree | |
921 next_runtime_abi_01_build_ivar_ref (location_t loc ATTRIBUTE_UNUSED, | |
922 tree base, tree id) | |
923 { | |
924 return objc_build_component_ref (base, id); | |
925 } | |
926 | |
927 /* We build super class references as we need them (but keep them once | |
928 built for the sake of efficiency). */ | |
929 | |
930 static tree | |
931 next_runtime_abi_01_get_class_super_ref (location_t loc ATTRIBUTE_UNUSED, | |
932 struct imp_entry *imp, bool inst_meth) | |
933 { | |
934 if (inst_meth) | |
935 { | |
936 if (!ucls_super_ref) | |
937 ucls_super_ref = | |
938 objc_build_component_ref (imp->class_decl, | |
939 get_identifier ("super_class")); | |
940 return ucls_super_ref; | |
941 } | |
942 else | |
943 { | |
944 if (!uucls_super_ref) | |
945 uucls_super_ref = | |
946 objc_build_component_ref (imp->meta_decl, | |
947 get_identifier ("super_class")); | |
948 return uucls_super_ref; | |
949 } | |
950 } | |
951 | |
952 static tree | |
953 next_runtime_abi_01_get_category_super_ref (location_t loc ATTRIBUTE_UNUSED, | |
954 struct imp_entry *imp, bool inst_meth) | |
955 { | |
956 tree super_name = CLASS_SUPER_NAME (imp->imp_template); | |
957 tree super_class; | |
958 | |
959 if (!flag_zero_link) | |
960 { | |
961 super_class = objc_get_class_reference (super_name); | |
962 | |
963 if (!inst_meth) | |
964 | |
965 /* If we are in a class method, we must retrieve the | |
966 _metaclass_ for the current class, pointed at by | |
967 the class's "isa" pointer. The following assumes that | |
968 "isa" is the first ivar in a class (which it must be). */ | |
969 super_class = | |
970 build_indirect_ref (input_location, | |
971 build_c_cast (input_location, | |
972 build_pointer_type (objc_class_type), | |
973 super_class), | |
974 RO_UNARY_STAR); | |
975 return super_class; | |
976 } | |
977 | |
978 /* else do it the slow way. */ | |
979 add_class_reference (super_name); | |
980 super_class = (inst_meth ? objc_get_class_decl : objc_get_meta_class_decl); | |
981 super_name = my_build_string_pointer (IDENTIFIER_LENGTH (super_name) + 1, | |
982 IDENTIFIER_POINTER (super_name)); | |
983 /* super_class = objc_get{Meta}Class("CLASS_SUPER_NAME"); */ | |
984 return build_function_call (input_location, | |
985 super_class, | |
986 build_tree_list (NULL_TREE, super_name)); | |
987 } | |
988 | |
989 static bool | |
990 next_runtime_abi_01_setup_const_string_class_decl (void) | |
991 { | |
992 if (!constant_string_global_id) | |
993 { | |
994 /* Hopefully, this should not represent a serious limitation. */ | |
995 char buf[BUFSIZE]; | |
996 snprintf (buf, BUFSIZE, "_%sClassReference", constant_string_class_name); | |
997 constant_string_global_id = get_identifier (buf); | |
998 } | |
999 | |
1000 string_class_decl = lookup_name (constant_string_global_id); | |
1001 | |
1002 return (string_class_decl != NULL_TREE); | |
1003 } | |
1004 | |
1005 static tree | |
1006 next_runtime_abi_01_build_const_string_constructor (location_t loc, tree string, | |
1007 int length) | |
1008 { | |
1009 tree constructor, fields, var; | |
1010 vec<constructor_elt, va_gc> *v = NULL; | |
1011 | |
1012 /* NeXT: (NSConstantString *) & ((__builtin_ObjCString) { isa, string, length }) */ | |
1013 fields = TYPE_FIELDS (internal_const_str_type); | |
1014 CONSTRUCTOR_APPEND_ELT (v, fields, | |
1015 build_unary_op (loc, ADDR_EXPR, string_class_decl, 0)); | |
1016 | |
1017 fields = DECL_CHAIN (fields); | |
1018 CONSTRUCTOR_APPEND_ELT (v, fields, | |
1019 build_unary_op (loc, ADDR_EXPR, string, 1)); | |
1020 | |
1021 /* ??? check if this should be long. */ | |
1022 fields = DECL_CHAIN (fields); | |
1023 CONSTRUCTOR_APPEND_ELT (v, fields, build_int_cst (NULL_TREE, length)); | |
1024 constructor = objc_build_constructor (internal_const_str_type, v); | |
1025 | |
1026 var = build_decl (input_location, CONST_DECL, NULL, TREE_TYPE (constructor)); | |
1027 DECL_INITIAL (var) = constructor; | |
1028 TREE_STATIC (var) = 1; | |
1029 DECL_CONTEXT (var) = NULL; | |
1030 OBJCMETA (var, objc_meta, meta_const_str); | |
1031 return var; | |
1032 } | |
1033 | |
1034 /* --- metadata templates --- */ | |
1035 | |
1036 /* This routine builds the following type: | |
1037 struct _prop_t { | |
1038 const char * const name; // property name | |
1039 const char * const attributes; // comma-delimited, encoded, | |
1040 // property attributes | |
1041 }; | |
1042 */ | |
1043 | |
1044 static GTY(()) tree objc_v1_property_template; | |
1045 | |
1046 static tree | |
1047 build_v1_property_template (void) | |
1048 { | |
1049 tree prop_record; | |
1050 tree decls, *chain = NULL; | |
1051 | |
1052 prop_record = objc_start_struct (get_identifier ("_prop_t")); | |
1053 /* const char * name */ | |
1054 decls = add_field_decl (string_type_node, "name", &chain); | |
1055 | |
1056 /* const char * attribute */ | |
1057 add_field_decl (string_type_node, "attribute", &chain); | |
1058 | |
1059 objc_finish_struct (prop_record, decls); | |
1060 return prop_record; | |
1061 } | |
1062 | |
1063 /* Build the following type: | |
1064 | |
1065 struct _objc_protocol_extension | |
1066 { | |
1067 uint32_t size; // sizeof (struct _objc_protocol_extension) | |
1068 struct objc_method_list *optional_instance_methods; | |
1069 struct objc_method_list *optional_class_methods; | |
1070 struct objc_prop_list *instance_properties; | |
1071 } | |
1072 */ | |
1073 | |
1074 static GTY(()) tree objc_protocol_extension_template; | |
1075 | |
1076 static void | |
1077 build_v1_objc_protocol_extension_template (void) | |
1078 { | |
1079 tree decls, *chain = NULL; | |
1080 | |
1081 objc_protocol_extension_template = | |
1082 objc_start_struct (get_identifier (UTAG_PROTOCOL_EXT)); | |
1083 | |
1084 /* uint32_t size; */ | |
1085 decls = add_field_decl (integer_type_node, "size", &chain); | |
1086 | |
1087 /* struct objc_method_list *optional_instance_methods; */ | |
1088 add_field_decl (objc_method_list_ptr, "optional_instance_methods", &chain); | |
1089 | |
1090 /* struct objc_method_list *optional_class_methods; */ | |
1091 add_field_decl (objc_method_list_ptr, "optional_class_methods", &chain); | |
1092 | |
1093 /* struct objc_prop_list *instance_properties; */ | |
1094 add_field_decl (objc_prop_list_ptr, "instance_properties", &chain); | |
1095 | |
1096 objc_finish_struct (objc_protocol_extension_template, decls); | |
1097 } | |
1098 | |
1099 /* This routine build following struct type: | |
1100 struct _objc_class_ext | |
1101 { | |
1102 uint32_t size; // sizeof(struct _objc_class_ext) | |
1103 const char *weak_ivar_layout; | |
1104 struct _prop_list_t *properties; | |
1105 } | |
1106 */ | |
1107 | |
1108 static GTY(()) tree objc_class_ext_template; | |
1109 | |
1110 static void | |
1111 build_objc_class_ext_template (void) | |
1112 { | |
1113 tree ptrt, decls, *chain = NULL; | |
1114 | |
1115 objc_class_ext_template = objc_start_struct (get_identifier (UTAG_CLASS_EXT)); | |
1116 | |
1117 /* uint32_t size; */ | |
1118 decls = add_field_decl (integer_type_node, "size", &chain); | |
1119 | |
1120 /* const char *weak_ivar_layout; */ | |
1121 add_field_decl (const_string_type_node, "weak_ivar_layout", &chain); | |
1122 | |
1123 /* struct _prop_list_t *properties; */ | |
1124 ptrt = build_pointer_type (xref_tag (RECORD_TYPE, | |
1125 get_identifier(UTAG_PROPERTY_LIST))); | |
1126 add_field_decl (ptrt, "properties", &chain); | |
1127 | |
1128 objc_finish_struct (objc_class_ext_template, decls); | |
1129 } | |
1130 | |
1131 static void | |
1132 build_metadata_templates (void) | |
1133 { | |
1134 | |
1135 if (!objc_method_template) | |
1136 objc_method_template = build_method_template (); | |
1137 | |
1138 | |
1139 | |
1140 } | |
1141 | |
1142 /* --- emit metadata --- */ | |
1143 | |
1144 static tree | |
1145 generate_v1_meth_descriptor_table (tree chain, tree protocol, | |
1146 const char *prefix, tree attr) | |
1147 { | |
1148 tree method_list_template, initlist, decl; | |
1149 int size; | |
1150 vec<constructor_elt, va_gc> *v = NULL; | |
1151 char buf[BUFSIZE]; | |
1152 | |
1153 if (!chain || !prefix) | |
1154 return NULL_TREE; | |
1155 | |
1156 if (!objc_method_prototype_template) | |
1157 objc_method_prototype_template = build_method_prototype_template (); | |
1158 | |
1159 size = list_length (chain); | |
1160 method_list_template = | |
1161 build_method_prototype_list_template (objc_method_prototype_template, | |
1162 size); | |
1163 snprintf (buf, BUFSIZE, "%s_%s", prefix, | |
1164 IDENTIFIER_POINTER (PROTOCOL_NAME (protocol))); | |
1165 | |
1166 decl = start_var_decl (method_list_template, buf); | |
1167 | |
1168 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); | |
1169 initlist = | |
1170 build_descriptor_table_initializer (objc_method_prototype_template, | |
1171 chain); | |
1172 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); | |
1173 /* Get into the right section. */ | |
1174 OBJCMETA (decl, objc_meta, attr); | |
1175 finish_var_decl (decl, objc_build_constructor (method_list_template, v)); | |
1176 return decl; | |
1177 } | |
1178 | |
1179 /* Build protocol ext = | |
1180 {size, opt_instance_meth, opt_class_meth, instance_props}; | |
1181 or NULL_TREE if none are present. */ | |
1182 | |
1183 static tree | |
1184 generate_v1_objc_protocol_extension (tree proto_interface, | |
1185 tree opt_instance_meth, | |
1186 tree opt_class_meth, | |
1187 tree instance_props) | |
1188 { | |
1189 int size; | |
1190 location_t loc; | |
1191 vec<constructor_elt, va_gc> *v = NULL; | |
1192 tree decl, expr; | |
1193 char buf[BUFSIZE]; | |
1194 | |
1195 /* If there are no extensions, then don't bother... */ | |
1196 if (!opt_instance_meth && !opt_class_meth && !instance_props) | |
1197 return NULL_TREE; | |
1198 | |
1199 if (!objc_protocol_extension_template) | |
1200 build_v1_objc_protocol_extension_template (); | |
1201 | |
1202 /* uint32_t size */ | |
1203 size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_protocol_extension_template)); | |
1204 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); | |
1205 | |
1206 /* Try for meaningful diagnostics. */ | |
1207 loc = DECL_SOURCE_LOCATION (PROTOCOL_FORWARD_DECL (proto_interface)); | |
1208 | |
1209 /* struct objc_method_list *optional_instance_methods; */ | |
1210 if (opt_instance_meth) | |
1211 expr = convert (objc_method_list_ptr, | |
1212 build_unary_op (loc, ADDR_EXPR, opt_instance_meth, 0)); | |
1213 else | |
1214 expr = convert (objc_method_list_ptr, null_pointer_node); | |
1215 | |
1216 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1217 | |
1218 /* struct objc_method_list *optional_class_methods; */ | |
1219 if (opt_class_meth) | |
1220 expr = convert (objc_method_list_ptr, | |
1221 build_unary_op (loc, ADDR_EXPR, opt_class_meth, 0)); | |
1222 else | |
1223 expr = convert (objc_method_list_ptr, null_pointer_node); | |
1224 | |
1225 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1226 /* struct objc_prop_list *instance_properties; */ | |
1227 if (instance_props) | |
1228 expr = convert (objc_prop_list_ptr, | |
1229 build_unary_op (loc, ADDR_EXPR, instance_props, 0)); | |
1230 else | |
1231 expr = convert (objc_prop_list_ptr, null_pointer_node); | |
1232 | |
1233 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1234 snprintf (buf, BUFSIZE, "_OBJC_ProtocolExt_%s", | |
1235 IDENTIFIER_POINTER (PROTOCOL_NAME (proto_interface))); | |
1236 | |
1237 decl = start_var_decl (objc_protocol_extension_template, buf); | |
1238 expr = objc_build_constructor (TREE_TYPE (decl), v); | |
1239 OBJCMETA (decl, objc_meta, meta_protocol_extension); | |
1240 finish_var_decl (decl, expr); | |
1241 return decl; | |
1242 } | |
1243 | |
1244 /* This routine builds the following type: | |
1245 struct _prop_list_t { | |
1246 uint32_t entsize; // sizeof (struct _prop_t) | |
1247 uint32_t prop_count; | |
1248 struct _prop_t prop_list [prop_count]; | |
1249 } | |
1250 */ | |
1251 | |
1252 static tree | |
1253 build_v1_property_list_template (tree list_type, int size) | |
1254 { | |
1255 tree property_list_t_record; | |
1256 tree array_type, decls, *chain = NULL; | |
1257 | |
1258 /* anonymous. */ | |
1259 property_list_t_record = objc_start_struct (NULL_TREE); | |
1260 | |
1261 /* uint32_t const entsize */ | |
1262 decls = add_field_decl (integer_type_node, "entsize", &chain); | |
1263 | |
1264 /* int prop_count */ | |
1265 add_field_decl (integer_type_node, "prop_count", &chain); | |
1266 | |
1267 /* struct _prop_t prop_list[]; */ | |
1268 array_type = build_sized_array_type (list_type, size); | |
1269 add_field_decl (array_type, "prop_list", &chain); | |
1270 | |
1271 objc_finish_struct (property_list_t_record, decls); | |
1272 return property_list_t_record; | |
1273 } | |
1274 | |
1275 /* This routine builds the initializer list to initialize the | |
1276 'struct _prop_t prop_list[]' field of 'struct _prop_list_t' meta-data. */ | |
1277 | |
1278 static tree | |
1279 build_v1_property_table_initializer (tree type, tree context) | |
1280 { | |
1281 tree x; | |
1282 vec<constructor_elt, va_gc> *inits = NULL; | |
1283 | |
1284 if (TREE_CODE (context) == PROTOCOL_INTERFACE_TYPE) | |
1285 x = CLASS_PROPERTY_DECL (context); | |
1286 else | |
1287 x = IMPL_PROPERTY_DECL (context); | |
1288 | |
1289 for (; x; x = TREE_CHAIN (x)) | |
1290 { | |
1291 vec<constructor_elt, va_gc> *elemlist = NULL; | |
1292 tree attribute, name_ident = PROPERTY_NAME (x); | |
1293 | |
1294 CONSTRUCTOR_APPEND_ELT (elemlist, NULL_TREE, | |
1295 add_objc_string (name_ident, prop_names_attr)); | |
1296 | |
1297 attribute = objc_v2_encode_prop_attr (x); | |
1298 CONSTRUCTOR_APPEND_ELT (elemlist, NULL_TREE, | |
1299 add_objc_string (attribute, prop_names_attr)); | |
1300 | |
1301 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, | |
1302 objc_build_constructor (type, elemlist)); | |
1303 } | |
1304 | |
1305 return objc_build_constructor (build_array_type (type, 0),inits); | |
1306 } | |
1307 | |
1308 /* This routine builds the 'struct _prop_list_t' variable declaration and | |
1309 initializes it with its initializer list. TYPE is 'struct _prop_list_t', | |
1310 NAME is the internal name of this variable, SIZE is number of properties | |
1311 for this class and LIST is the initializer list for its 'prop_list' field. */ | |
1312 | |
1313 static tree | |
1314 generate_v1_property_table (tree context, tree klass_ctxt) | |
1315 { | |
1316 tree x, decl, initlist, property_list_template; | |
1317 bool is_proto = false; | |
1318 vec<constructor_elt, va_gc> *inits = NULL; | |
1319 int init_val, size = 0; | |
1320 char buf[BUFSIZE]; | |
1321 | |
1322 if (context) | |
1323 { | |
1324 gcc_assert (TREE_CODE (context) == PROTOCOL_INTERFACE_TYPE); | |
1325 x = CLASS_PROPERTY_DECL (context); | |
1326 is_proto = true; | |
1327 } | |
1328 else | |
1329 x = IMPL_PROPERTY_DECL (klass_ctxt); | |
1330 | |
1331 for (; x; x = TREE_CHAIN (x)) | |
1332 size++; | |
1333 | |
1334 if (size == 0) | |
1335 return NULL_TREE; | |
1336 | |
1337 if (!objc_v1_property_template) | |
1338 objc_v1_property_template = build_v1_property_template (); | |
1339 | |
1340 property_list_template = | |
1341 build_v1_property_list_template (objc_v1_property_template, | |
1342 size); | |
1343 initlist = build_v1_property_table_initializer (objc_v1_property_template, | |
1344 is_proto ? context | |
1345 : klass_ctxt); | |
1346 | |
1347 init_val = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_v1_property_template)); | |
1348 if (is_proto) | |
1349 snprintf (buf, BUFSIZE, "_OBJC_ProtocolPropList_%s", | |
1350 IDENTIFIER_POINTER (PROTOCOL_NAME (context))); | |
1351 else | |
1352 snprintf (buf, BUFSIZE, "_OBJC_ClassPropList_%s", | |
1353 IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt))); | |
1354 | |
1355 decl = start_var_decl (property_list_template, buf); | |
1356 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, init_val)); | |
1357 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); | |
1358 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); | |
1359 x = objc_build_constructor (TREE_TYPE (decl), inits); | |
1360 OBJCMETA (decl, objc_meta, meta_proplist); | |
1361 finish_var_decl (decl, x); | |
1362 return decl; | |
1363 } | |
1364 | |
1365 static tree | |
1366 generate_v1_protocol_list (tree i_or_p, tree klass_ctxt) | |
1367 { | |
1368 tree array_type, ptype, refs_decl, lproto, e, plist, attr; | |
1369 int size = 0; | |
1370 vec<constructor_elt, va_gc> *v = NULL; | |
1371 char buf[BUFSIZE]; | |
1372 | |
1373 switch (TREE_CODE (i_or_p)) | |
1374 { | |
1375 case CLASS_INTERFACE_TYPE: | |
1376 case CATEGORY_INTERFACE_TYPE: | |
1377 plist = CLASS_PROTOCOL_LIST (i_or_p); | |
1378 break; | |
1379 case PROTOCOL_INTERFACE_TYPE: | |
1380 plist = PROTOCOL_LIST (i_or_p); | |
1381 break; | |
1382 default: | |
1383 gcc_unreachable (); | |
1384 } | |
1385 | |
1386 /* Compute size. */ | |
1387 for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) | |
1388 if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE | |
1389 && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto))) | |
1390 size++; | |
1391 | |
1392 /* Build initializer. */ | |
1393 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, 0)); | |
1394 e = build_int_cst (build_pointer_type (objc_protocol_template), size); | |
1395 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); | |
1396 | |
1397 for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto)) | |
1398 { | |
1399 tree pval = TREE_VALUE (lproto); | |
1400 | |
1401 if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE | |
1402 && PROTOCOL_FORWARD_DECL (pval)) | |
1403 { | |
1404 tree fwref = PROTOCOL_FORWARD_DECL (pval); | |
1405 location_t loc = DECL_SOURCE_LOCATION (fwref) ; | |
1406 e = build_unary_op (loc, ADDR_EXPR, fwref, 0); | |
1407 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, e); | |
1408 } | |
1409 } | |
1410 | |
1411 /* static struct objc_protocol *refs[n]; */ | |
1412 switch (TREE_CODE (i_or_p)) | |
1413 { | |
1414 case PROTOCOL_INTERFACE_TYPE: | |
1415 snprintf (buf, BUFSIZE, "_OBJC_ProtocolRefs_%s", | |
1416 IDENTIFIER_POINTER (PROTOCOL_NAME (i_or_p))); | |
1417 attr = meta_proto_ref; | |
1418 break; | |
1419 case CLASS_INTERFACE_TYPE: | |
1420 snprintf (buf, BUFSIZE, "_OBJC_ClassProtocols_%s", | |
1421 IDENTIFIER_POINTER (CLASS_NAME (i_or_p))); | |
1422 attr = meta_clas_prot; | |
1423 break; | |
1424 case CATEGORY_INTERFACE_TYPE: | |
1425 snprintf (buf, BUFSIZE, "_OBJC_CategoryProtocols_%s_%s", | |
1426 IDENTIFIER_POINTER (CLASS_NAME (klass_ctxt)), | |
1427 IDENTIFIER_POINTER (CLASS_SUPER_NAME (klass_ctxt))); | |
1428 attr = meta_catg_prot; | |
1429 break; | |
1430 default: | |
1431 gcc_unreachable (); | |
1432 } | |
1433 | |
1434 ptype = build_pointer_type (objc_protocol_template); | |
1435 array_type = build_sized_array_type (ptype, size + 3); | |
1436 refs_decl = start_var_decl (array_type, buf); | |
1437 | |
1438 OBJCMETA (refs_decl, objc_meta, attr); | |
1439 finish_var_decl (refs_decl, | |
1440 objc_build_constructor (TREE_TYPE (refs_decl), v)); | |
1441 | |
1442 return refs_decl; | |
1443 } | |
1444 | |
1445 static tree | |
1446 build_v1_protocol_initializer (tree type, tree protocol_name, tree protocol_list, | |
1447 tree inst_methods, tree class_methods, | |
1448 tree protocol_ext) | |
1449 { | |
1450 tree expr, ttyp; | |
1451 location_t loc; | |
1452 vec<constructor_elt, va_gc> *inits = NULL; | |
1453 | |
1454 if (!objc_protocol_extension_template) | |
1455 build_v1_objc_protocol_extension_template (); | |
1456 | |
1457 /* TODO: find a better representation of location from the inputs. */ | |
1458 loc = UNKNOWN_LOCATION; | |
1459 ttyp = build_pointer_type (objc_protocol_extension_template); | |
1460 /* Instead of jamming the protocol version number into the isa, we pass | |
1461 either a pointer to the protocol extension - or NULL. */ | |
1462 if (protocol_ext) | |
1463 expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, protocol_ext, 0)); | |
1464 else | |
1465 expr = convert (ttyp, null_pointer_node); | |
1466 | |
1467 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); | |
1468 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_name); | |
1469 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, protocol_list); | |
1470 | |
1471 ttyp = objc_method_proto_list_ptr; | |
1472 if (inst_methods) | |
1473 expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); | |
1474 else | |
1475 expr = convert (ttyp, null_pointer_node); | |
1476 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); | |
1477 | |
1478 if (class_methods) | |
1479 expr = convert (ttyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); | |
1480 else | |
1481 expr = convert (ttyp, null_pointer_node); | |
1482 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, expr); | |
1483 | |
1484 return objc_build_constructor (type, inits); | |
1485 } | |
1486 | |
1487 /* An updated version of generate_protocols () that emit the protocol | |
1488 extension for ABI=1. */ | |
1489 | |
1490 /* For each protocol which was referenced either from a @protocol() | |
1491 expression, or because a class/category implements it (then a | |
1492 pointer to the protocol is stored in the struct describing the | |
1493 class/category), we create a statically allocated instance of the | |
1494 Protocol class. The code is written in such a way as to generate | |
1495 as few Protocol objects as possible; we generate a unique Protocol | |
1496 instance for each protocol, and we don't generate a Protocol | |
1497 instance if the protocol is never referenced (either from a | |
1498 @protocol() or from a class/category implementation). These | |
1499 statically allocated objects can be referred to via the static | |
1500 (that is, private to this module) symbols _OBJC_PROTOCOL_n. | |
1501 | |
1502 The statically allocated Protocol objects that we generate here | |
1503 need to be fixed up at runtime in order to be used: the 'isa' | |
1504 pointer of the objects need to be set up to point to the 'Protocol' | |
1505 class, as known at runtime. | |
1506 | |
1507 The NeXT runtime fixes up all protocols at program startup time, | |
1508 before main() is entered. It uses a low-level trick to look up all | |
1509 those symbols, then loops on them and fixes them up. */ | |
1510 | |
1511 /* TODO: finish getting rid of passing stuff around in globals. */ | |
1512 | |
1513 static GTY(()) tree V1_Protocol_OPT_NST_METHODS_decl; | |
1514 static GTY(()) tree V1_Protocol_OPT_CLS_METHODS_decl; | |
1515 static GTY(()) tree V1_ProtocolExt_decl; | |
1516 static GTY(()) tree V1_Property_decl; | |
1517 | |
1518 static void | |
1519 generate_v1_protocols (void) | |
1520 { | |
1521 tree p; | |
1522 | |
1523 /* If a protocol was directly referenced, pull in indirect references. */ | |
1524 for (p = protocol_chain; p; p = TREE_CHAIN (p)) | |
1525 if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p)) | |
1526 generate_protocol_references (PROTOCOL_LIST (p)); | |
1527 | |
1528 for (p = protocol_chain; p; p = TREE_CHAIN (p)) | |
1529 { | |
1530 tree decl, encoding, initlist, protocol_name_expr; | |
1531 tree refs_type, refs_decl, refs_expr; | |
1532 location_t loc; | |
1533 tree nst_methods = PROTOCOL_NST_METHODS (p); | |
1534 tree cls_methods = PROTOCOL_CLS_METHODS (p); | |
1535 | |
1536 /* If protocol wasn't referenced, don't generate any code. */ | |
1537 decl = PROTOCOL_FORWARD_DECL (p); | |
1538 | |
1539 if (!decl) | |
1540 continue; | |
1541 | |
1542 /* Make sure we link in the Protocol class. */ | |
1543 add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME)); | |
1544 | |
1545 while (nst_methods) | |
1546 { | |
1547 if (! METHOD_ENCODING (nst_methods)) | |
1548 { | |
1549 encoding = encode_method_prototype (nst_methods); | |
1550 METHOD_ENCODING (nst_methods) = encoding; | |
1551 } | |
1552 nst_methods = TREE_CHAIN (nst_methods); | |
1553 } | |
1554 | |
1555 UOBJC_INSTANCE_METHODS_decl = | |
1556 generate_v1_meth_descriptor_table (PROTOCOL_NST_METHODS (p), p, | |
1557 "_OBJC_ProtocolInstanceMethods", | |
1558 meta_proto_nst_meth); | |
1559 | |
1560 while (cls_methods) | |
1561 { | |
1562 if (! METHOD_ENCODING (cls_methods)) | |
1563 { | |
1564 encoding = encode_method_prototype (cls_methods); | |
1565 METHOD_ENCODING (cls_methods) = encoding; | |
1566 } | |
1567 | |
1568 cls_methods = TREE_CHAIN (cls_methods); | |
1569 } | |
1570 | |
1571 UOBJC_CLASS_METHODS_decl = | |
1572 generate_v1_meth_descriptor_table (PROTOCOL_CLS_METHODS (p), p, | |
1573 "_OBJC_ProtocolClassMethods", | |
1574 meta_proto_cls_meth); | |
1575 | |
1576 /* There should be no optional methods for ABI-0 - but we need to | |
1577 check all this here before the lists are made. */ | |
1578 nst_methods = PROTOCOL_OPTIONAL_NST_METHODS (p); | |
1579 while (nst_methods) | |
1580 { | |
1581 if (! METHOD_ENCODING (nst_methods)) | |
1582 { | |
1583 encoding = encode_method_prototype (nst_methods); | |
1584 METHOD_ENCODING (nst_methods) = encoding; | |
1585 } | |
1586 nst_methods = TREE_CHAIN (nst_methods); | |
1587 } | |
1588 | |
1589 V1_Protocol_OPT_NST_METHODS_decl = | |
1590 generate_v1_meth_descriptor_table (PROTOCOL_OPTIONAL_NST_METHODS (p), p, | |
1591 "_OBJC_OptionalProtocolInstanceMethods", | |
1592 meta_proto_nst_meth); | |
1593 | |
1594 cls_methods = PROTOCOL_OPTIONAL_CLS_METHODS (p); | |
1595 while (cls_methods) | |
1596 { | |
1597 if (! METHOD_ENCODING (cls_methods)) | |
1598 { | |
1599 encoding = encode_method_prototype (cls_methods); | |
1600 METHOD_ENCODING (cls_methods) = encoding; | |
1601 } | |
1602 | |
1603 cls_methods = TREE_CHAIN (cls_methods); | |
1604 } | |
1605 | |
1606 V1_Protocol_OPT_CLS_METHODS_decl = | |
1607 generate_v1_meth_descriptor_table (PROTOCOL_OPTIONAL_CLS_METHODS (p), p, | |
1608 "_OBJC_OptionalProtocolClassMethods", | |
1609 meta_proto_cls_meth); | |
1610 | |
1611 if (PROTOCOL_LIST (p)) | |
1612 refs_decl = generate_v1_protocol_list (p, objc_implementation_context); | |
1613 else | |
1614 refs_decl = 0; | |
1615 | |
1616 /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */ | |
1617 protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names); | |
1618 /* TODO: more locations to be fixed up... */ | |
1619 loc = UNKNOWN_LOCATION; | |
1620 refs_type = | |
1621 build_pointer_type (build_pointer_type (objc_protocol_template)); | |
1622 if (refs_decl) | |
1623 refs_expr = convert (refs_type, | |
1624 build_unary_op (loc, ADDR_EXPR, refs_decl, 0)); | |
1625 else | |
1626 refs_expr = convert (refs_type, null_pointer_node); | |
1627 | |
1628 if (flag_objc_abi < 1) | |
1629 { | |
1630 /* Original ABI. */ | |
1631 initlist = | |
1632 build_protocol_initializer (TREE_TYPE (decl), | |
1633 protocol_name_expr, refs_expr, | |
1634 UOBJC_INSTANCE_METHODS_decl, | |
1635 UOBJC_CLASS_METHODS_decl); | |
1636 finish_var_decl (decl, initlist); | |
1637 continue; | |
1638 } | |
1639 | |
1640 /* else - V1 extensions. */ | |
1641 | |
1642 V1_Property_decl = | |
1643 generate_v1_property_table (p, NULL_TREE); | |
1644 | |
1645 V1_ProtocolExt_decl = | |
1646 generate_v1_objc_protocol_extension (p, | |
1647 V1_Protocol_OPT_NST_METHODS_decl, | |
1648 V1_Protocol_OPT_CLS_METHODS_decl, | |
1649 V1_Property_decl); | |
1650 | |
1651 initlist = build_v1_protocol_initializer (TREE_TYPE (decl), | |
1652 protocol_name_expr, refs_expr, | |
1653 UOBJC_INSTANCE_METHODS_decl, | |
1654 UOBJC_CLASS_METHODS_decl, | |
1655 V1_ProtocolExt_decl); | |
1656 finish_var_decl (decl, initlist); | |
1657 } | |
1658 } | |
1659 | |
1660 static tree | |
1661 generate_dispatch_table (tree chain, const char *name, tree attr) | |
1662 { | |
1663 tree decl, method_list_template, initlist; | |
1664 vec<constructor_elt, va_gc> *v = NULL; | |
1665 int size;; | |
1666 | |
1667 if (!chain || !name || !(size = list_length (chain))) | |
1668 return NULL_TREE; | |
1669 | |
1670 if (!objc_method_template) | |
1671 objc_method_template = build_method_template (); | |
1672 | |
1673 method_list_template = build_method_list_template (objc_method_template, | |
1674 size); | |
1675 initlist = build_dispatch_table_initializer (objc_method_template, chain); | |
1676 | |
1677 decl = start_var_decl (method_list_template, name); | |
1678 | |
1679 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, integer_zero_node); | |
1680 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
1681 build_int_cst (integer_type_node, size)); | |
1682 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, initlist); | |
1683 | |
1684 OBJCMETA (decl, objc_meta, attr); | |
1685 finish_var_decl (decl, | |
1686 objc_build_constructor (TREE_TYPE (decl), v)); | |
1687 | |
1688 return decl; | |
1689 } | |
1690 | |
1691 /* Init a category. */ | |
1692 static tree | |
1693 build_v1_category_initializer (tree type, tree cat_name, tree class_name, | |
1694 tree inst_methods, tree class_methods, | |
1695 tree protocol_list, tree property_list, | |
1696 location_t loc) | |
1697 { | |
1698 tree expr, ltyp; | |
1699 vec<constructor_elt, va_gc> *v = NULL; | |
1700 | |
1701 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, cat_name); | |
1702 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, class_name); | |
1703 | |
1704 ltyp = objc_method_list_ptr; | |
1705 if (inst_methods) | |
1706 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, inst_methods, 0)); | |
1707 else | |
1708 expr = convert (ltyp, null_pointer_node); | |
1709 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1710 | |
1711 if (class_methods) | |
1712 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_methods, 0)); | |
1713 else | |
1714 expr = convert (ltyp, null_pointer_node); | |
1715 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1716 | |
1717 /* protocol_list = */ | |
1718 ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); | |
1719 if (protocol_list) | |
1720 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); | |
1721 else | |
1722 expr = convert (ltyp, null_pointer_node); | |
1723 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1724 | |
1725 if (flag_objc_abi >= 1) | |
1726 { | |
1727 int val = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_category_template)); | |
1728 expr = build_int_cst (NULL_TREE, val); | |
1729 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1730 ltyp = objc_prop_list_ptr; | |
1731 if (property_list) | |
1732 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); | |
1733 else | |
1734 expr = convert (ltyp, null_pointer_node); | |
1735 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1736 } | |
1737 | |
1738 return objc_build_constructor (type, v); | |
1739 } | |
1740 | |
1741 /* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */ | |
1742 /* TODO: get rid of passing stuff around in globals. */ | |
1743 static void | |
1744 generate_v1_category (struct imp_entry *impent) | |
1745 { | |
1746 tree initlist, cat_name_expr, class_name_expr; | |
1747 tree protocol_decl, category, cat_decl; | |
1748 tree inst_methods = NULL_TREE, class_methods = NULL_TREE; | |
1749 tree cat = impent->imp_context; | |
1750 location_t loc; | |
1751 char buf[BUFSIZE]; | |
1752 | |
1753 cat_decl = impent->class_decl; | |
1754 loc = DECL_SOURCE_LOCATION (cat_decl); | |
1755 | |
1756 add_class_reference (CLASS_NAME (cat)); | |
1757 cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names); | |
1758 class_name_expr = add_objc_string (CLASS_NAME (cat), class_names); | |
1759 | |
1760 category = lookup_category (impent->imp_template, CLASS_SUPER_NAME (cat)); | |
1761 | |
1762 if (category && CLASS_PROTOCOL_LIST (category)) | |
1763 { | |
1764 generate_protocol_references (CLASS_PROTOCOL_LIST (category)); | |
1765 protocol_decl = generate_v1_protocol_list (category, cat); | |
1766 } | |
1767 else | |
1768 protocol_decl = 0; | |
1769 | |
1770 if (flag_objc_abi >= 1) | |
1771 V1_Property_decl = generate_v1_property_table (NULL_TREE, cat); | |
1772 else | |
1773 V1_Property_decl = NULL_TREE; | |
1774 | |
1775 if (CLASS_NST_METHODS (cat)) | |
1776 { | |
1777 snprintf (buf, BUFSIZE, "_OBJC_CategoryInstanceMethods_%s_%s", | |
1778 IDENTIFIER_POINTER (CLASS_NAME (cat)), | |
1779 IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); | |
1780 inst_methods = generate_dispatch_table (CLASS_NST_METHODS (cat), buf, | |
1781 meta_cati_meth); | |
1782 } | |
1783 | |
1784 if (CLASS_CLS_METHODS (cat)) | |
1785 { | |
1786 snprintf (buf, BUFSIZE, "_OBJC_CategoryClassMethods_%s_%s", | |
1787 IDENTIFIER_POINTER (CLASS_NAME (cat)), | |
1788 IDENTIFIER_POINTER (CLASS_SUPER_NAME (cat))); | |
1789 class_methods = generate_dispatch_table (CLASS_CLS_METHODS (cat), buf, | |
1790 meta_catc_meth); | |
1791 } | |
1792 | |
1793 initlist = build_v1_category_initializer (TREE_TYPE (cat_decl), | |
1794 cat_name_expr, class_name_expr, | |
1795 inst_methods, class_methods, | |
1796 protocol_decl, V1_Property_decl, | |
1797 loc); | |
1798 | |
1799 finish_var_decl (cat_decl, initlist); | |
1800 impent->class_decl = cat_decl; | |
1801 } | |
1802 | |
1803 /* This routine builds the class extension used by v1 NeXT. */ | |
1804 | |
1805 static tree | |
1806 generate_objc_class_ext (tree property_list, tree context) | |
1807 { | |
1808 tree decl, expr, ltyp; | |
1809 tree weak_ivar_layout_tree; | |
1810 int size; | |
1811 location_t loc; | |
1812 vec<constructor_elt, va_gc> *v = NULL; | |
1813 char buf[BUFSIZE]; | |
1814 | |
1815 /* TODO: pass the loc in or find it from args. */ | |
1816 loc = UNKNOWN_LOCATION; | |
1817 | |
1818 /* const char *weak_ivar_layout | |
1819 TODO: Figure the ivar layouts out... */ | |
1820 weak_ivar_layout_tree = NULL_TREE; | |
1821 | |
1822 if (!property_list && !weak_ivar_layout_tree) | |
1823 return NULL_TREE; | |
1824 | |
1825 if (!objc_class_ext_template) | |
1826 build_objc_class_ext_template (); | |
1827 | |
1828 /* uint32_t size */ | |
1829 size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (objc_class_ext_template)); | |
1830 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, size)); | |
1831 | |
1832 ltyp = const_string_type_node; | |
1833 if (weak_ivar_layout_tree) | |
1834 expr = convert (ltyp, weak_ivar_layout_tree); | |
1835 else | |
1836 expr = convert (ltyp, null_pointer_node); | |
1837 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1838 | |
1839 /* struct _prop_list_t *properties; */ | |
1840 ltyp = objc_prop_list_ptr; | |
1841 if (property_list) | |
1842 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, property_list, 0)); | |
1843 else | |
1844 expr = convert (ltyp, null_pointer_node); | |
1845 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1846 | |
1847 snprintf (buf, BUFSIZE, "_OBJC_ClassExt_%s", | |
1848 IDENTIFIER_POINTER (CLASS_NAME (context))); | |
1849 decl = start_var_decl (objc_class_ext_template, buf); | |
1850 expr = objc_build_constructor (TREE_TYPE (decl), v); | |
1851 OBJCMETA (decl, objc_meta, meta_class_extension); | |
1852 finish_var_decl (decl, expr); | |
1853 return decl; | |
1854 } | |
1855 | |
1856 /* struct _objc_class { | |
1857 struct objc_class *isa; | |
1858 struct objc_class *super_class; | |
1859 char *name; | |
1860 long version; | |
1861 long info; | |
1862 long instance_size; | |
1863 struct objc_ivar_list *ivars; | |
1864 struct objc_method_list *methods; | |
1865 struct objc_cache *cache; | |
1866 struct objc_protocol_list *protocols; | |
1867 #if ABI >= 1 | |
1868 const char *ivar_layout; | |
1869 struct _objc_class_ext *ext; | |
1870 #else | |
1871 void *sel_id; | |
1872 void *gc_object_type; | |
1873 #endif | |
1874 }; */ | |
1875 | |
1876 static tree | |
1877 build_v1_shared_structure_initializer (tree type, tree isa, tree super, | |
1878 tree name, tree size, int status, | |
1879 tree dispatch_table, tree ivar_list, | |
1880 tree protocol_list, tree class_ext) | |
1881 { | |
1882 tree expr, ltyp; | |
1883 location_t loc; | |
1884 vec<constructor_elt, va_gc> *v = NULL; | |
1885 | |
1886 /* TODO: fish the location out of the input data. */ | |
1887 loc = UNKNOWN_LOCATION; | |
1888 | |
1889 /* isa = */ | |
1890 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, isa); | |
1891 | |
1892 /* super_class = */ | |
1893 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, super); | |
1894 | |
1895 /* name = */ | |
1896 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, default_conversion (name)); | |
1897 | |
1898 /* version = */ | |
1899 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
1900 build_int_cst (long_integer_type_node, 0)); | |
1901 | |
1902 /* info = */ | |
1903 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
1904 build_int_cst (long_integer_type_node, status)); | |
1905 | |
1906 /* instance_size = */ | |
1907 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
1908 convert (long_integer_type_node, size)); | |
1909 | |
1910 /* objc_ivar_list = */ | |
1911 ltyp = objc_ivar_list_ptr; | |
1912 if (ivar_list) | |
1913 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, ivar_list, 0)); | |
1914 else | |
1915 expr = convert (ltyp, null_pointer_node); | |
1916 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1917 | |
1918 /* objc_method_list = */ | |
1919 ltyp = objc_method_list_ptr; | |
1920 if (dispatch_table) | |
1921 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, dispatch_table, 0)); | |
1922 else | |
1923 expr = convert (ltyp, null_pointer_node); | |
1924 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1925 | |
1926 ltyp = build_pointer_type (xref_tag (RECORD_TYPE, | |
1927 get_identifier ("objc_cache"))); | |
1928 /* method_cache = */ | |
1929 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, convert (ltyp, null_pointer_node)); | |
1930 | |
1931 /* protocol_list = */ | |
1932 ltyp = build_pointer_type (build_pointer_type (objc_protocol_template)); | |
1933 if (protocol_list) | |
1934 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, protocol_list, 0)); | |
1935 else | |
1936 expr = convert (ltyp, null_pointer_node); | |
1937 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1938 | |
1939 if (flag_objc_abi >= 1) | |
1940 { | |
1941 /* TODO: figure out the ivar_layout stuff. */ | |
1942 expr = convert (const_string_type_node, null_pointer_node); | |
1943 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1944 if (!objc_class_ext_template) | |
1945 build_objc_class_ext_template (); | |
1946 ltyp = build_pointer_type (objc_class_ext_template); | |
1947 if (class_ext) | |
1948 expr = convert (ltyp, build_unary_op (loc, ADDR_EXPR, class_ext, 0)); | |
1949 else | |
1950 expr = convert (ltyp, null_pointer_node); | |
1951 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
1952 } | |
1953 else | |
1954 { | |
1955 /* sel_id = NULL */ | |
1956 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, null_pointer_node); | |
1957 | |
1958 /* gc_object_type = NULL */ | |
1959 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, null_pointer_node); | |
1960 } | |
1961 return objc_build_constructor (type, v); | |
1962 } | |
1963 | |
1964 static tree | |
1965 generate_ivars_list (tree chain, const char *name, tree attr) | |
1966 { | |
1967 tree initlist, ivar_list_template, decl; | |
1968 int size; | |
1969 vec<constructor_elt, va_gc> *inits = NULL; | |
1970 | |
1971 if (!chain) | |
1972 return NULL_TREE; | |
1973 | |
1974 if (!objc_ivar_template) | |
1975 objc_ivar_template = build_ivar_template (); | |
1976 | |
1977 size = ivar_list_length (chain); | |
1978 | |
1979 generating_instance_variables = 1; | |
1980 ivar_list_template = build_ivar_list_template (objc_ivar_template, size); | |
1981 initlist = build_ivar_list_initializer (objc_ivar_template, chain); | |
1982 generating_instance_variables = 0; | |
1983 | |
1984 decl = start_var_decl (ivar_list_template, name); | |
1985 | |
1986 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, build_int_cst (NULL_TREE, size)); | |
1987 CONSTRUCTOR_APPEND_ELT (inits, NULL_TREE, initlist); | |
1988 | |
1989 OBJCMETA (decl, objc_meta, attr); | |
1990 finish_var_decl (decl, | |
1991 objc_build_constructor (TREE_TYPE (decl), inits)); | |
1992 | |
1993 return decl; | |
1994 } | |
1995 | |
1996 /* static struct objc_class _OBJC_METACLASS_Foo={ ... }; | |
1997 static struct objc_class _OBJC_CLASS_Foo={ ... }; */ | |
1998 | |
1999 static void | |
2000 generate_v1_class_structs (struct imp_entry *impent) | |
2001 { | |
2002 tree name_expr, super_expr, root_expr, class_decl, meta_decl; | |
2003 tree my_root_id, my_super_id; | |
2004 tree cast_type, initlist, protocol_decl; | |
2005 tree class_ext_decl = NULL_TREE, props = NULL_TREE; | |
2006 tree inst_methods = NULL_TREE, class_methods = NULL_TREE; | |
2007 tree chain, inst_ivars = NULL_TREE, class_ivars = NULL_TREE; | |
2008 int cls_flags; | |
2009 location_t loc; | |
2010 char buf[BUFSIZE]; | |
2011 | |
2012 /* objc_implementation_context = impent->imp_context; | |
2013 implementation_template = impent->imp_template;*/ | |
2014 class_decl = impent->class_decl; | |
2015 meta_decl = impent->meta_decl; | |
2016 cls_flags = impent->has_cxx_cdtors ? CLS_HAS_CXX_STRUCTORS : 0 ; | |
2017 | |
2018 loc = DECL_SOURCE_LOCATION (impent->class_decl); | |
2019 | |
2020 if (flag_objc_abi >= 1) | |
2021 { | |
2022 /* ABI=1 additions. */ | |
2023 props = generate_v1_property_table (NULL_TREE, impent->imp_context); | |
2024 class_ext_decl = generate_objc_class_ext (props, impent->imp_context); | |
2025 } | |
2026 | |
2027 my_super_id = CLASS_SUPER_NAME (impent->imp_template); | |
2028 if (my_super_id) | |
2029 { | |
2030 add_class_reference (my_super_id); | |
2031 | |
2032 /* Compute "my_root_id" - this is required for code generation. | |
2033 the "isa" for all meta class structures points to the root of | |
2034 the inheritance hierarchy (e.g. "__Object")... */ | |
2035 my_root_id = my_super_id; | |
2036 do | |
2037 { | |
2038 tree my_root_int = lookup_interface (my_root_id); | |
2039 | |
2040 if (my_root_int && CLASS_SUPER_NAME (my_root_int)) | |
2041 my_root_id = CLASS_SUPER_NAME (my_root_int); | |
2042 else | |
2043 break; | |
2044 } | |
2045 while (1); | |
2046 super_expr = add_objc_string (my_super_id, class_names); | |
2047 } | |
2048 else | |
2049 { | |
2050 /* No super class. */ | |
2051 my_root_id = CLASS_NAME (impent->imp_template); | |
2052 super_expr = null_pointer_node; | |
2053 } | |
2054 | |
2055 /* Install class `isa' and `super' pointers at runtime. */ | |
2056 cast_type = build_pointer_type (objc_class_template); | |
2057 super_expr = build_c_cast (loc, cast_type, super_expr); | |
2058 | |
2059 root_expr = add_objc_string (my_root_id, class_names); | |
2060 root_expr = build_c_cast (loc, cast_type, root_expr); | |
2061 | |
2062 if (CLASS_PROTOCOL_LIST (impent->imp_template)) | |
2063 { | |
2064 generate_protocol_references (CLASS_PROTOCOL_LIST (impent->imp_template)); | |
2065 protocol_decl = generate_v1_protocol_list (impent->imp_template, | |
2066 impent->imp_context); | |
2067 } | |
2068 else | |
2069 protocol_decl = NULL_TREE; | |
2070 | |
2071 if (CLASS_CLS_METHODS (impent->imp_context)) | |
2072 { | |
2073 snprintf (buf, BUFSIZE, "_OBJC_ClassMethods_%s", | |
2074 IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); | |
2075 class_methods = generate_dispatch_table (CLASS_CLS_METHODS (impent->imp_context), | |
2076 buf, meta_clac_meth); | |
2077 } | |
2078 | |
2079 if (CLASS_SUPER_NAME (impent->imp_template) == NULL_TREE | |
2080 && (chain = TYPE_FIELDS (objc_class_template))) | |
2081 { | |
2082 snprintf (buf, BUFSIZE, "_OBJC_ClassIvars_%s", | |
2083 IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); | |
2084 class_ivars = generate_ivars_list (chain, buf, meta_clac_vars); | |
2085 } | |
2086 /* TODO: get rid of hidden passing of stuff in globals. */ | |
2087 /* UOBJC_INSTANCE/CLASS_Variables_decl made in generate_ivarlists(). */ | |
2088 | |
2089 name_expr = add_objc_string (CLASS_NAME (impent->imp_template), class_names); | |
2090 | |
2091 /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */ | |
2092 | |
2093 initlist = build_v1_shared_structure_initializer | |
2094 (TREE_TYPE (meta_decl), | |
2095 root_expr, super_expr, name_expr, | |
2096 convert (integer_type_node, TYPE_SIZE_UNIT (objc_class_template)), | |
2097 CLS_META, class_methods, class_ivars, | |
2098 protocol_decl, NULL_TREE); | |
2099 | |
2100 finish_var_decl (meta_decl, initlist); | |
2101 impent->meta_decl = meta_decl; | |
2102 | |
2103 /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */ | |
2104 if (CLASS_NST_METHODS (impent->imp_context)) | |
2105 { | |
2106 snprintf (buf, BUFSIZE, "_OBJC_InstanceMethods_%s", | |
2107 IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); | |
2108 inst_methods = generate_dispatch_table (CLASS_NST_METHODS (impent->imp_context), | |
2109 buf, meta_clai_meth); | |
2110 } | |
2111 | |
2112 if ((chain = CLASS_IVARS (impent->imp_template))) | |
2113 { | |
2114 snprintf (buf, BUFSIZE, "_OBJC_InstanceIvars_%s", | |
2115 IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); | |
2116 inst_ivars = generate_ivars_list (chain, buf, meta_clai_vars); | |
2117 } | |
2118 | |
2119 initlist = build_v1_shared_structure_initializer | |
2120 (TREE_TYPE (class_decl), | |
2121 build_unary_op (loc, ADDR_EXPR, meta_decl, 0), | |
2122 super_expr, name_expr, | |
2123 convert (integer_type_node, | |
2124 TYPE_SIZE_UNIT (CLASS_STATIC_TEMPLATE (impent->imp_template))), | |
2125 CLS_FACTORY | cls_flags, inst_methods, inst_ivars, | |
2126 protocol_decl, class_ext_decl); | |
2127 | |
2128 finish_var_decl (class_decl, initlist); | |
2129 impent->class_decl = class_decl; | |
2130 } | |
2131 | |
2132 /* --- Output NeXT V1 Metadata --- */ | |
2133 | |
2134 /* Create the initial value for the `defs' field of _objc_symtab. | |
2135 This is a CONSTRUCTOR. */ | |
2136 | |
2137 static tree | |
2138 init_def_list (tree type) | |
2139 { | |
2140 tree expr; | |
2141 location_t loc; | |
2142 struct imp_entry *impent; | |
2143 vec<constructor_elt, va_gc> *v = NULL; | |
2144 | |
2145 if (imp_count) | |
2146 for (impent = imp_list; impent; impent = impent->next) | |
2147 { | |
2148 if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) | |
2149 { | |
2150 loc = DECL_SOURCE_LOCATION (impent->class_decl); | |
2151 expr = build_unary_op (loc, | |
2152 ADDR_EXPR, impent->class_decl, 0); | |
2153 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
2154 } | |
2155 } | |
2156 | |
2157 if (cat_count) | |
2158 for (impent = imp_list; impent; impent = impent->next) | |
2159 { | |
2160 if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE) | |
2161 { | |
2162 loc = DECL_SOURCE_LOCATION (impent->class_decl); | |
2163 expr = build_unary_op (loc, | |
2164 ADDR_EXPR, impent->class_decl, 0); | |
2165 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, expr); | |
2166 } | |
2167 } | |
2168 | |
2169 return objc_build_constructor (type, v); | |
2170 } | |
2171 | |
2172 /* Take care of defining and initializing _OBJC_SYMBOLS. */ | |
2173 | |
2174 /* Predefine the following data type: | |
2175 | |
2176 struct _objc_symtab | |
2177 { | |
2178 long sel_ref_cnt; | |
2179 SEL *refs; | |
2180 short cls_def_cnt; | |
2181 short cat_def_cnt; | |
2182 void *defs[cls_def_cnt + cat_def_cnt]; | |
2183 }; */ | |
2184 | |
2185 static void | |
2186 build_objc_symtab_template (void) | |
2187 { | |
2188 tree fields, *chain = NULL; | |
2189 | |
2190 objc_symtab_template = objc_start_struct (get_identifier (UTAG_SYMTAB)); | |
2191 | |
2192 /* long sel_ref_cnt; */ | |
2193 fields = add_field_decl (long_integer_type_node, "sel_ref_cnt", &chain); | |
2194 | |
2195 /* SEL *refs; */ | |
2196 add_field_decl (build_pointer_type (objc_selector_type), "refs", &chain); | |
2197 | |
2198 /* short cls_def_cnt; */ | |
2199 add_field_decl (short_integer_type_node, "cls_def_cnt", &chain); | |
2200 | |
2201 /* short cat_def_cnt; */ | |
2202 add_field_decl (short_integer_type_node, "cat_def_cnt", &chain); | |
2203 | |
2204 if (imp_count || cat_count) | |
2205 { | |
2206 /* void *defs[imp_count + cat_count (+ 1)]; */ | |
2207 /* NB: The index is one less than the size of the array. */ | |
2208 int index = imp_count + cat_count; | |
2209 tree array_type = build_sized_array_type (ptr_type_node, index); | |
2210 add_field_decl (array_type, "defs", &chain); | |
2211 } | |
2212 | |
2213 objc_finish_struct (objc_symtab_template, fields); | |
2214 } | |
2215 /* Construct the initial value for all of _objc_symtab. */ | |
2216 | |
2217 static tree | |
2218 init_objc_symtab (tree type) | |
2219 { | |
2220 vec<constructor_elt, va_gc> *v = NULL; | |
2221 | |
2222 /* sel_ref_cnt = { ..., 5, ... } */ | |
2223 | |
2224 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
2225 build_int_cst (long_integer_type_node, 0)); | |
2226 | |
2227 /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */ | |
2228 | |
2229 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
2230 convert (build_pointer_type (objc_selector_type), | |
2231 integer_zero_node)); | |
2232 | |
2233 /* cls_def_cnt = { ..., 5, ... } */ | |
2234 | |
2235 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
2236 build_int_cst (short_integer_type_node, imp_count)); | |
2237 | |
2238 /* cat_def_cnt = { ..., 5, ... } */ | |
2239 | |
2240 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, | |
2241 build_int_cst (short_integer_type_node, cat_count)); | |
2242 | |
2243 /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */ | |
2244 | |
2245 if (imp_count || cat_count) | |
2246 { | |
2247 tree field = TYPE_FIELDS (type); | |
2248 field = DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (DECL_CHAIN (field)))); | |
2249 | |
2250 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init_def_list (TREE_TYPE (field))); | |
2251 } | |
2252 | |
2253 return objc_build_constructor (type, v); | |
2254 } | |
2255 | |
2256 /* Create the declaration of _OBJC_SYMBOLS, with type `struct _objc_symtab' | |
2257 and initialized appropriately. */ | |
2258 | |
2259 static void | |
2260 generate_objc_symtab_decl (void) | |
2261 { | |
2262 build_objc_symtab_template (); | |
2263 UOBJC_SYMBOLS_decl = start_var_decl (objc_symtab_template, "_OBJC_Symbols"); | |
2264 /* Allow the runtime to mark meta-data such that it can be assigned to target | |
2265 specific sections by the back-end. */ | |
2266 OBJCMETA (UOBJC_SYMBOLS_decl, objc_meta, meta_symtab); | |
2267 finish_var_decl (UOBJC_SYMBOLS_decl, | |
2268 init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl))); | |
2269 } | |
2270 | |
2271 /* Any target implementing NeXT ObjC m32 ABI has to ensure that objects | |
2272 refer to, and define, symbols that enforce linkage of classes into the | |
2273 executable image, preserving unix archive semantics. | |
2274 | |
2275 At present (4.8), the only targets implementing this are Darwin; these | |
2276 use top level asms to implement a scheme (see config/darwin-c.c). The | |
2277 latter method is a hack, but compatible with LTO see also PR48109 for | |
2278 further discussion and other possible methods. */ | |
2279 | |
2280 static void | |
2281 handle_next_class_ref (tree chain ATTRIBUTE_UNUSED) | |
2282 { | |
2283 if (targetcm.objc_declare_unresolved_class_reference) | |
2284 { | |
2285 const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain)); | |
2286 char *string = (char *) alloca (strlen (name) + 30); | |
2287 sprintf (string, ".objc_class_name_%s", name); | |
2288 targetcm.objc_declare_unresolved_class_reference (string); | |
2289 } | |
2290 } | |
2291 | |
2292 static void | |
2293 handle_next_impent (struct imp_entry *impent ATTRIBUTE_UNUSED) | |
2294 { | |
2295 if (targetcm.objc_declare_class_definition) | |
2296 { | |
2297 char buf[BUFSIZE]; | |
2298 | |
2299 switch (TREE_CODE (impent->imp_context)) | |
2300 { | |
2301 case CLASS_IMPLEMENTATION_TYPE: | |
2302 snprintf (buf, BUFSIZE, ".objc_class_name_%s", | |
2303 IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))); | |
2304 break; | |
2305 case CATEGORY_IMPLEMENTATION_TYPE: | |
2306 snprintf (buf, BUFSIZE, "*.objc_category_name_%s_%s", | |
2307 IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context)), | |
2308 IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context))); | |
2309 break; | |
2310 default: | |
2311 return; | |
2312 } | |
2313 targetcm.objc_declare_class_definition (buf); | |
2314 } | |
2315 } | |
2316 | |
2317 static void | |
2318 generate_classref_translation_entry (tree chain) | |
2319 { | |
2320 tree expr, decl, type; | |
2321 | |
2322 decl = TREE_PURPOSE (chain); | |
2323 type = TREE_TYPE (decl); | |
2324 | |
2325 expr = add_objc_string (TREE_VALUE (chain), class_names); | |
2326 expr = convert (type, expr); /* cast! */ | |
2327 | |
2328 /* This is a class reference. It is re-written by the runtime, | |
2329 but will be optimized away unless we force it. */ | |
2330 DECL_PRESERVE_P (decl) = 1; | |
2331 OBJCMETA (decl, objc_meta, meta_class_reference); | |
2332 finish_var_decl (decl, expr); | |
2333 return; | |
2334 } | |
2335 | |
2336 static void | |
2337 objc_generate_v1_next_metadata (void) | |
2338 { | |
2339 struct imp_entry *impent; | |
2340 tree chain, attr; | |
2341 long vers; | |
2342 | |
2343 /* FIXME: Make sure that we generate no metadata if there is nothing | |
2344 to put into it. */ | |
2345 | |
2346 if (objc_static_instances) | |
2347 gcc_unreachable (); /* Not for NeXT */ | |
2348 | |
2349 build_metadata_templates (); | |
2350 objc_implementation_context = | |
2351 implementation_template = | |
2352 UOBJC_CLASS_decl = | |
2353 UOBJC_METACLASS_decl = NULL_TREE; | |
2354 | |
2355 for (impent = imp_list; impent; impent = impent->next) | |
2356 { | |
2357 | |
2358 /* If -gen-decls is present, Dump the @interface of each class. | |
2359 TODO: Dump the classes in the order they were found, rather than in | |
2360 reverse order as we are doing now. */ | |
2361 if (flag_gen_declaration) | |
2362 dump_interface (gen_declaration_file, impent->imp_context); | |
2363 | |
2364 /* all of the following reference the string pool... */ | |
2365 if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE) | |
2366 generate_v1_class_structs (impent); | |
2367 else | |
2368 generate_v1_category (impent); | |
2369 } | |
2370 | |
2371 /* If we are using an array of selectors, we must always | |
2372 finish up the array decl even if no selectors were used. */ | |
2373 build_next_selector_translation_table (); | |
2374 | |
2375 if (protocol_chain) | |
2376 generate_v1_protocols (); | |
2377 | |
2378 /* Pass summary information to the runtime. */ | |
2379 if (imp_count || cat_count) | |
2380 generate_objc_symtab_decl (); | |
2381 | |
2382 vers = OBJC_VERSION; | |
2383 attr = build_tree_list (objc_meta, meta_modules); | |
2384 build_module_descriptor (vers, attr); | |
2385 | |
2386 /* Dump the class references. This forces the appropriate classes | |
2387 to be linked into the executable image, preserving unix archive | |
2388 semantics. */ | |
2389 for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain)) | |
2390 { | |
2391 handle_next_class_ref (chain); | |
2392 if (TREE_PURPOSE (chain)) | |
2393 generate_classref_translation_entry (chain); | |
2394 } | |
2395 | |
2396 for (impent = imp_list; impent; impent = impent->next) | |
2397 handle_next_impent (impent); | |
2398 | |
2399 /* Emit the strings tables. */ | |
2400 generate_strings (); | |
2401 } | |
2402 | |
2403 /* --- exceptions stuff --- */ | |
2404 | |
2405 /* Predefine the following data type: | |
2406 | |
2407 struct _objc_exception_data | |
2408 { | |
2409 int buf[OBJC_JBLEN]; | |
2410 void *pointers[4]; | |
2411 }; */ | |
2412 | |
2413 /* The following yuckiness should prevent users from having to #include | |
2414 <setjmp.h> in their code... */ | |
2415 | |
2416 /* Define to a harmless positive value so the below code doesn't die. */ | |
2417 #ifndef OBJC_JBLEN | |
2418 #define OBJC_JBLEN 18 | |
2419 #endif | |
2420 | |
2421 static void | |
2422 build_next_objc_exception_stuff (void) | |
2423 { | |
2424 tree decls, temp_type, *chain = NULL; | |
2425 | |
2426 objc_exception_data_template | |
2427 = objc_start_struct (get_identifier (UTAG_EXCDATA)); | |
2428 | |
2429 /* int buf[OBJC_JBLEN]; */ | |
2430 | |
2431 temp_type = build_sized_array_type (integer_type_node, OBJC_JBLEN); | |
2432 decls = add_field_decl (temp_type, "buf", &chain); | |
2433 | |
2434 /* void *pointers[4]; */ | |
2435 | |
2436 temp_type = build_sized_array_type (ptr_type_node, 4); | |
2437 add_field_decl (temp_type, "pointers", &chain); | |
2438 | |
2439 objc_finish_struct (objc_exception_data_template, decls); | |
2440 | |
2441 /* int _setjmp(...); */ | |
2442 /* If the user includes <setjmp.h>, this shall be superseded by | |
2443 'int _setjmp(jmp_buf);' */ | |
2444 temp_type = build_varargs_function_type_list (integer_type_node, NULL_TREE); | |
2445 objc_setjmp_decl | |
2446 = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE); | |
2447 | |
2448 /* id objc_exception_extract(struct _objc_exception_data *); */ | |
2449 temp_type | |
2450 = build_function_type_list (objc_object_type, | |
2451 build_pointer_type (objc_exception_data_template), | |
2452 NULL_TREE); | |
2453 objc_exception_extract_decl | |
2454 = add_builtin_function (TAG_EXCEPTIONEXTRACT, temp_type, 0, NOT_BUILT_IN, NULL, | |
2455 NULL_TREE); | |
2456 /* void objc_exception_try_enter(struct _objc_exception_data *); */ | |
2457 /* void objc_exception_try_exit(struct _objc_exception_data *); */ | |
2458 temp_type | |
2459 = build_function_type_list (void_type_node, | |
2460 build_pointer_type (objc_exception_data_template), | |
2461 NULL_TREE); | |
2462 objc_exception_try_enter_decl | |
2463 = add_builtin_function (TAG_EXCEPTIONTRYENTER, temp_type, 0, NOT_BUILT_IN, NULL, | |
2464 NULL_TREE); | |
2465 objc_exception_try_exit_decl | |
2466 = add_builtin_function (TAG_EXCEPTIONTRYEXIT, temp_type, 0, NOT_BUILT_IN, NULL, | |
2467 NULL_TREE); | |
2468 | |
2469 /* int objc_exception_match(id, id); */ | |
2470 temp_type | |
2471 = build_function_type_list (integer_type_node, | |
2472 objc_object_type, objc_object_type, NULL_TREE); | |
2473 objc_exception_match_decl | |
2474 = add_builtin_function (TAG_EXCEPTIONMATCH, temp_type, 0, NOT_BUILT_IN, NULL, | |
2475 NULL_TREE); | |
2476 | |
2477 /* id objc_assign_ivar (id, id, unsigned int); */ | |
2478 /* id objc_assign_ivar_Fast (id, id, unsigned int) | |
2479 __attribute__ ((hard_coded_address (OFFS_ASSIGNIVAR_FAST))); */ | |
2480 temp_type | |
2481 = build_function_type_list (objc_object_type, | |
2482 objc_object_type, | |
2483 objc_object_type, | |
2484 unsigned_type_node, | |
2485 NULL_TREE); | |
2486 objc_assign_ivar_decl | |
2487 = add_builtin_function (TAG_ASSIGNIVAR, temp_type, 0, NOT_BUILT_IN, | |
2488 NULL, NULL_TREE); | |
2489 #ifdef OFFS_ASSIGNIVAR_FAST | |
2490 objc_assign_ivar_fast_decl | |
2491 = add_builtin_function (TAG_ASSIGNIVAR_FAST, temp_type, 0, | |
2492 NOT_BUILT_IN, NULL, NULL_TREE); | |
2493 DECL_ATTRIBUTES (objc_assign_ivar_fast_decl) | |
2494 = tree_cons (get_identifier ("hard_coded_address"), | |
2495 build_int_cst (NULL_TREE, OFFS_ASSIGNIVAR_FAST), | |
2496 NULL_TREE); | |
2497 #else | |
2498 /* Default to slower ivar method. */ | |
2499 objc_assign_ivar_fast_decl = objc_assign_ivar_decl; | |
2500 #endif | |
2501 | |
2502 /* id objc_assign_global (id, id *); */ | |
2503 /* id objc_assign_strongCast (id, id *); */ | |
2504 temp_type = build_function_type_list (objc_object_type, | |
2505 objc_object_type, | |
2506 build_pointer_type (objc_object_type), | |
2507 NULL_TREE); | |
2508 objc_assign_global_decl | |
2509 = add_builtin_function (TAG_ASSIGNGLOBAL, temp_type, 0, NOT_BUILT_IN, NULL, | |
2510 NULL_TREE); | |
2511 objc_assign_strong_cast_decl | |
2512 = add_builtin_function (TAG_ASSIGNSTRONGCAST, temp_type, 0, NOT_BUILT_IN, NULL, | |
2513 NULL_TREE); | |
2514 } | |
2515 | |
2516 /* --- NeXT V1 SJLJ Exceptions --- */ | |
2517 | |
2518 /* Build "objc_exception_try_exit(&_stack)". */ | |
2519 | |
2520 static tree | |
2521 next_sjlj_build_try_exit (struct objc_try_context **ctcp) | |
2522 { | |
2523 tree t; | |
2524 t = build_fold_addr_expr_loc (input_location, (*ctcp)->stack_decl); | |
2525 t = tree_cons (NULL, t, NULL); | |
2526 t = build_function_call (input_location, | |
2527 objc_exception_try_exit_decl, t); | |
2528 return t; | |
2529 } | |
2530 | |
2531 /* Build | |
2532 objc_exception_try_enter (&_stack); | |
2533 if (_setjmp(&_stack.buf)) | |
2534 ; | |
2535 else | |
2536 ; | |
2537 Return the COND_EXPR. Note that the THEN and ELSE fields are left | |
2538 empty, ready for the caller to fill them in. */ | |
2539 | |
2540 static tree | |
2541 next_sjlj_build_enter_and_setjmp (struct objc_try_context **ctcp) | |
2542 { | |
2543 tree t, enter, sj, cond; | |
2544 | |
2545 t = build_fold_addr_expr_loc (input_location, (*ctcp)->stack_decl); | |
2546 t = tree_cons (NULL, t, NULL); | |
2547 enter = build_function_call (input_location, | |
2548 objc_exception_try_enter_decl, t); | |
2549 | |
2550 t = objc_build_component_ref ((*ctcp)->stack_decl, | |
2551 get_identifier ("buf")); | |
2552 t = build_fold_addr_expr_loc (input_location, t); | |
2553 #ifdef OBJCPLUS | |
2554 /* Convert _setjmp argument to type that is expected. */ | |
2555 if (prototype_p (TREE_TYPE (objc_setjmp_decl))) | |
2556 t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t); | |
2557 else | |
2558 t = convert (ptr_type_node, t); | |
2559 #else | |
2560 t = convert (ptr_type_node, t); | |
2561 #endif | |
2562 t = tree_cons (NULL, t, NULL); | |
2563 sj = build_function_call (input_location, | |
2564 objc_setjmp_decl, t); | |
2565 | |
2566 cond = build2 (COMPOUND_EXPR, TREE_TYPE (sj), enter, sj); | |
2567 cond = c_common_truthvalue_conversion (input_location, cond); | |
2568 | |
2569 return build3 (COND_EXPR, void_type_node, cond, NULL, NULL); | |
2570 } | |
2571 | |
2572 /* Build: | |
2573 | |
2574 DECL = objc_exception_extract(&_stack); */ | |
2575 | |
2576 static tree | |
2577 next_sjlj_build_exc_extract (struct objc_try_context **ctcp, tree decl) | |
2578 { | |
2579 tree t; | |
2580 | |
2581 t = build_fold_addr_expr_loc (input_location, (*ctcp)->stack_decl); | |
2582 t = tree_cons (NULL, t, NULL); | |
2583 t = build_function_call (input_location, | |
2584 objc_exception_extract_decl, t); | |
2585 t = convert (TREE_TYPE (decl), t); | |
2586 t = build2 (MODIFY_EXPR, void_type_node, decl, t); | |
2587 | |
2588 return t; | |
2589 } | |
2590 | |
2591 /* Build | |
2592 if (objc_exception_match(obj_get_class(TYPE), _caught) | |
2593 BODY | |
2594 else if (...) | |
2595 ... | |
2596 else | |
2597 { | |
2598 _rethrow = _caught; | |
2599 objc_exception_try_exit(&_stack); | |
2600 } | |
2601 from the sequence of CATCH_EXPRs in the current try context. */ | |
2602 | |
2603 static tree | |
2604 next_sjlj_build_catch_list (struct objc_try_context **ctcp) | |
2605 { | |
2606 tree_stmt_iterator i = tsi_start ((*ctcp)->catch_list); | |
2607 tree catch_seq, t; | |
2608 tree *last = &catch_seq; | |
2609 bool saw_id = false; | |
2610 | |
2611 for (; !tsi_end_p (i); tsi_next (&i)) | |
2612 { | |
2613 tree stmt = tsi_stmt (i); | |
2614 tree type = CATCH_TYPES (stmt); | |
2615 tree body = CATCH_BODY (stmt); | |
2616 | |
2617 if (type != error_mark_node | |
2618 && objc_is_object_id (TREE_TYPE (type))) | |
2619 { | |
2620 *last = body; | |
2621 saw_id = true; | |
2622 break; | |
2623 } | |
2624 else | |
2625 { | |
2626 tree args, cond; | |
2627 | |
2628 if (type == error_mark_node) | |
2629 cond = error_mark_node; | |
2630 else | |
2631 { | |
2632 args = tree_cons (NULL, (*ctcp)->caught_decl, NULL); | |
2633 t = objc_get_class_reference (OBJC_TYPE_NAME (TREE_TYPE (type))); | |
2634 args = tree_cons (NULL, t, args); | |
2635 t = build_function_call (input_location, | |
2636 objc_exception_match_decl, args); | |
2637 cond = c_common_truthvalue_conversion (input_location, t); | |
2638 } | |
2639 t = build3 (COND_EXPR, void_type_node, cond, body, NULL); | |
2640 SET_EXPR_LOCATION (t, EXPR_LOCATION (stmt)); | |
2641 | |
2642 *last = t; | |
2643 last = &COND_EXPR_ELSE (t); | |
2644 } | |
2645 } | |
2646 | |
2647 if (!saw_id) | |
2648 { | |
2649 t = build2 (MODIFY_EXPR, void_type_node, (*ctcp)->rethrow_decl, | |
2650 (*ctcp)->caught_decl); | |
2651 SET_EXPR_LOCATION (t, (*ctcp)->end_catch_locus); | |
2652 append_to_statement_list (t, last); | |
2653 | |
2654 t = next_sjlj_build_try_exit (ctcp); | |
2655 SET_EXPR_LOCATION (t, (*ctcp)->end_catch_locus); | |
2656 append_to_statement_list (t, last); | |
2657 } | |
2658 | |
2659 return catch_seq; | |
2660 } | |
2661 | |
2662 /* Build a complete @try-@catch-@finally block for legacy Darwin setjmp | |
2663 exception handling. We aim to build: | |
2664 | |
2665 { | |
2666 struct _objc_exception_data _stack; | |
2667 id _rethrow = 0; | |
2668 try | |
2669 { | |
2670 objc_exception_try_enter (&_stack); | |
2671 if (_setjmp(&_stack.buf)) | |
2672 { | |
2673 id _caught = objc_exception_extract(&_stack); | |
2674 objc_exception_try_enter (&_stack); | |
2675 if (_setjmp(&_stack.buf)) | |
2676 _rethrow = objc_exception_extract(&_stack); | |
2677 else | |
2678 CATCH-LIST | |
2679 } | |
2680 else | |
2681 TRY-BLOCK | |
2682 } | |
2683 finally | |
2684 { | |
2685 if (!_rethrow) | |
2686 objc_exception_try_exit(&_stack); | |
2687 FINALLY-BLOCK | |
2688 if (_rethrow) | |
2689 objc_exception_throw(_rethrow); | |
2690 } | |
2691 } | |
2692 | |
2693 If CATCH-LIST is empty, we can omit all of the block containing | |
2694 "_caught" except for the setting of _rethrow. Note the use of | |
2695 a real TRY_FINALLY_EXPR here, which is not involved in EH per-se, | |
2696 but handles goto and other exits from the block. */ | |
2697 | |
2698 static tree | |
2699 next_sjlj_build_try_catch_finally (struct objc_try_context **ctcp) | |
2700 { | |
2701 tree rethrow_decl, stack_decl, t; | |
2702 tree catch_seq, try_fin, bind; | |
2703 struct objc_try_context *cur_try_context = *ctcp; | |
2704 | |
2705 /* Create the declarations involved. */ | |
2706 t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); | |
2707 stack_decl = objc_create_temporary_var (t, NULL); | |
2708 cur_try_context->stack_decl = stack_decl; | |
2709 | |
2710 rethrow_decl = objc_create_temporary_var (objc_object_type, NULL); | |
2711 cur_try_context->rethrow_decl = rethrow_decl; | |
2712 TREE_CHAIN (rethrow_decl) = stack_decl; | |
2713 | |
2714 /* Build the outermost variable binding level. */ | |
2715 bind = build3 (BIND_EXPR, void_type_node, rethrow_decl, NULL, NULL); | |
2716 SET_EXPR_LOCATION (bind, cur_try_context->try_locus); | |
2717 TREE_SIDE_EFFECTS (bind) = 1; | |
2718 | |
2719 /* Initialize rethrow_decl. */ | |
2720 t = build2 (MODIFY_EXPR, void_type_node, rethrow_decl, | |
2721 convert (objc_object_type, null_pointer_node)); | |
2722 SET_EXPR_LOCATION (t, cur_try_context->try_locus); | |
2723 append_to_statement_list (t, &BIND_EXPR_BODY (bind)); | |
2724 | |
2725 /* Build the outermost TRY_FINALLY_EXPR. */ | |
2726 try_fin = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); | |
2727 SET_EXPR_LOCATION (try_fin, cur_try_context->try_locus); | |
2728 TREE_SIDE_EFFECTS (try_fin) = 1; | |
2729 append_to_statement_list (try_fin, &BIND_EXPR_BODY (bind)); | |
2730 | |
2731 /* Create the complete catch sequence. */ | |
2732 if (cur_try_context->catch_list) | |
2733 { | |
2734 tree caught_decl = objc_build_exc_ptr (ctcp); | |
2735 catch_seq = build_stmt (input_location, BIND_EXPR, caught_decl, NULL, NULL); | |
2736 TREE_SIDE_EFFECTS (catch_seq) = 1; | |
2737 | |
2738 t = next_sjlj_build_exc_extract (ctcp, caught_decl); | |
2739 append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); | |
2740 | |
2741 t = next_sjlj_build_enter_and_setjmp (ctcp); | |
2742 COND_EXPR_THEN (t) = next_sjlj_build_exc_extract (ctcp, rethrow_decl); | |
2743 COND_EXPR_ELSE (t) = next_sjlj_build_catch_list (ctcp); | |
2744 append_to_statement_list (t, &BIND_EXPR_BODY (catch_seq)); | |
2745 } | |
2746 else | |
2747 catch_seq = next_sjlj_build_exc_extract (ctcp, rethrow_decl); | |
2748 SET_EXPR_LOCATION (catch_seq, cur_try_context->end_try_locus); | |
2749 | |
2750 /* Build the main register-and-try if statement. */ | |
2751 t = next_sjlj_build_enter_and_setjmp (ctcp); | |
2752 SET_EXPR_LOCATION (t, cur_try_context->try_locus); | |
2753 COND_EXPR_THEN (t) = catch_seq; | |
2754 COND_EXPR_ELSE (t) = cur_try_context->try_body; | |
2755 TREE_OPERAND (try_fin, 0) = t; | |
2756 | |
2757 /* Build the complete FINALLY statement list. */ | |
2758 t = next_sjlj_build_try_exit (ctcp); | |
2759 t = build_stmt (input_location, COND_EXPR, | |
2760 c_common_truthvalue_conversion | |
2761 (input_location, rethrow_decl), | |
2762 NULL, t); | |
2763 SET_EXPR_LOCATION (t, cur_try_context->finally_locus); | |
2764 append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); | |
2765 | |
2766 append_to_statement_list (cur_try_context->finally_body, | |
2767 &TREE_OPERAND (try_fin, 1)); | |
2768 | |
2769 t = tree_cons (NULL, rethrow_decl, NULL); | |
2770 t = build_function_call (input_location, | |
2771 objc_exception_throw_decl, t); | |
2772 t = build_stmt (input_location, COND_EXPR, | |
2773 c_common_truthvalue_conversion (input_location, | |
2774 rethrow_decl), | |
2775 t, NULL); | |
2776 SET_EXPR_LOCATION (t, cur_try_context->end_finally_locus); | |
2777 append_to_statement_list (t, &TREE_OPERAND (try_fin, 1)); | |
2778 | |
2779 return bind; | |
2780 } | |
2781 | |
2782 /* We do not expect this to be used at the moment. | |
2783 If (a) it is possible to implement unwinder exceptions. | |
2784 (b) we do it... then it might be possibly useful. | |
2785 */ | |
2786 static GTY(()) tree objc_eh_personality_decl; | |
2787 | |
2788 static tree | |
2789 objc_eh_runtime_type (tree type) | |
2790 { | |
2791 tree ident, eh_id, decl, str; | |
2792 | |
2793 gcc_unreachable (); | |
2794 if (type == error_mark_node) | |
2795 { | |
2796 /* Use 'ErrorMarkNode' as class name when error_mark_node is found | |
2797 to prevent an ICE. Note that we know that the compiler will | |
2798 terminate with an error and this 'ErrorMarkNode' class name will | |
2799 never be actually used. */ | |
2800 ident = get_identifier ("ErrorMarkNode"); | |
2801 goto make_err_class; | |
2802 } | |
2803 | |
2804 if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type))) | |
2805 { | |
2806 ident = get_identifier ("id"); | |
2807 goto make_err_class; | |
2808 } | |
2809 | |
2810 if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type))) | |
2811 { | |
2812 #ifdef OBJCPLUS | |
2813 /* This routine is also called for c++'s catch clause; in which case, | |
2814 we use c++'s typeinfo decl. */ | |
2815 return build_eh_type_type (type); | |
2816 #else | |
2817 error ("non-objective-c type %qT cannot be caught", type); | |
2818 ident = get_identifier ("ErrorMarkNode"); | |
2819 goto make_err_class; | |
2820 #endif | |
2821 } | |
2822 else | |
2823 ident = OBJC_TYPE_NAME (TREE_TYPE (type)); | |
2824 | |
2825 make_err_class: | |
2826 /* If this class was already referenced, then it will be output during | |
2827 meta-data emission, so we don't need to do it here. */ | |
2828 decl = get_objc_string_decl (ident, class_names); | |
2829 eh_id = add_objc_string (ident, class_names); | |
2830 if (!decl) | |
2831 { | |
2832 /* Not found ... so we need to build it - from the freshly-entered id. */ | |
2833 decl = get_objc_string_decl (ident, class_names); | |
2834 str = my_build_string (IDENTIFIER_LENGTH (ident) + 1, | |
2835 IDENTIFIER_POINTER (ident)); | |
2836 /* We have to finalize this var here, because this might be called after | |
2837 all the other metadata strings have been emitted. */ | |
2838 finish_var_decl (decl, str); | |
2839 } | |
2840 return eh_id; | |
2841 } | |
2842 | |
2843 /* For NeXT ABI 0 and 1, the personality routines are just those of the | |
2844 underlying language. */ | |
2845 | |
2846 static tree | |
2847 objc_eh_personality (void) | |
2848 { | |
2849 if (!objc_eh_personality_decl) | |
2850 #ifndef OBJCPLUS | |
2851 objc_eh_personality_decl = build_personality_function ("gcc"); | |
2852 #else | |
2853 objc_eh_personality_decl = build_personality_function ("gxx"); | |
2854 #endif | |
2855 return objc_eh_personality_decl; | |
2856 } | |
2857 | |
2858 /* --- interfaces --- */ | |
2859 | |
2860 static tree | |
2861 build_throw_stmt (location_t loc, tree throw_expr, bool rethrown ATTRIBUTE_UNUSED) | |
2862 { | |
2863 tree t; | |
2864 vec<tree, va_gc> *parms; | |
2865 vec_alloc (parms, 1); | |
2866 /* A throw is just a call to the runtime throw function with the | |
2867 object as a parameter. */ | |
2868 parms->quick_push (throw_expr); | |
2869 t = build_function_call_vec (loc, vNULL, objc_exception_throw_decl, parms, | |
2870 NULL); | |
2871 vec_free (parms); | |
2872 return add_stmt (t); | |
2873 } | |
2874 | |
2875 /* Build __builtin_eh_pointer, or the moral equivalent. In the case | |
2876 of Darwin, we'll arrange for it to be initialized (and associated | |
2877 with a binding) later. */ | |
2878 | |
2879 static tree | |
2880 objc_build_exc_ptr (struct objc_try_context **cur_try_context) | |
2881 { | |
2882 if (flag_objc_sjlj_exceptions) | |
2883 { | |
2884 tree var = (*cur_try_context)->caught_decl; | |
2885 if (!var) | |
2886 { | |
2887 var = objc_create_temporary_var (objc_object_type, NULL); | |
2888 (*cur_try_context)->caught_decl = var; | |
2889 } | |
2890 return var; | |
2891 } | |
2892 else | |
2893 { | |
2894 tree t; | |
2895 t = builtin_decl_explicit (BUILT_IN_EH_POINTER); | |
2896 t = build_call_expr (t, 1, integer_zero_node); | |
2897 return fold_convert (objc_object_type, t); | |
2898 } | |
2899 } | |
2900 | |
2901 static tree | |
2902 begin_catch (struct objc_try_context **cur_try_context, tree type, | |
2903 tree decl, tree compound, bool ellipsis ATTRIBUTE_UNUSED) | |
2904 { | |
2905 tree t; | |
2906 /* Record the data for the catch in the try context so that we can | |
2907 finalize it later. We treat ellipsis the same way as catching | |
2908 with 'id xyz'. */ | |
2909 t = build_stmt (input_location, CATCH_EXPR, type, compound); | |
2910 (*cur_try_context)->current_catch = t; | |
2911 | |
2912 /* Initialize the decl from the EXC_PTR_EXPR we get from the runtime. */ | |
2913 t = objc_build_exc_ptr (cur_try_context); | |
2914 t = convert (TREE_TYPE (decl), t); | |
2915 return build2 (MODIFY_EXPR, void_type_node, decl, t); | |
2916 } | |
2917 | |
2918 static void | |
2919 finish_catch (struct objc_try_context **cur_try_context, tree current_catch) | |
2920 { | |
2921 append_to_statement_list (current_catch, &((*cur_try_context)->catch_list)); | |
2922 } | |
2923 | |
2924 static tree | |
2925 finish_try_stmt (struct objc_try_context **cur_try_context) | |
2926 { | |
2927 tree stmt; | |
2928 struct objc_try_context *c = *cur_try_context; | |
2929 /* If we're doing Darwin setjmp exceptions, build the big nasty. */ | |
2930 if (flag_objc_sjlj_exceptions) | |
2931 { | |
2932 bool save = in_late_binary_op; | |
2933 in_late_binary_op = true; | |
2934 if (!c->finally_body) | |
2935 { | |
2936 c->finally_locus = input_location; | |
2937 c->end_finally_locus = input_location; | |
2938 } | |
2939 stmt = next_sjlj_build_try_catch_finally (cur_try_context); | |
2940 in_late_binary_op = save; | |
2941 } | |
2942 else | |
2943 /* This doesn't happen at the moment... but maybe one day... */ | |
2944 { | |
2945 /* Otherwise, nest the CATCH inside a FINALLY. */ | |
2946 stmt = c->try_body; | |
2947 if (c->catch_list) | |
2948 stmt = build_stmt (c->try_locus, TRY_CATCH_EXPR, stmt, c->catch_list); | |
2949 if (c->finally_body) | |
2950 stmt = build_stmt (c->try_locus, TRY_FINALLY_EXPR, stmt, c->finally_body); | |
2951 } | |
2952 return stmt; | |
2953 } | |
2954 | |
2955 #include "gt-objc-objc-next-runtime-abi-01.h" |