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