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

source code of gcc/objc/objc-next-runtime-abi-01.cc