111
|
1 /* Next Runtime (ABI-0/1) private.
|
131
|
2 Copyright (C) 2011-2018 Free Software Foundation, Inc.
|
111
|
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;
|
131
|
1665 int size;
|
111
|
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"
|