BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / gcc-2.3.3 / cp-gc.c
CommitLineData
d60bb9a0
C
1/* Garbage collection primitives for GNU C++.
2 Copyright (C) 1992 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann (tiemann@cygnus.com)
4
5This file is part of GNU CC.
6
7GNU CC 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 2, or (at your option)
10any later version.
11
12GNU CC 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 GNU CC; see the file COPYING. If not, write to
19the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21
22#include "config.h"
23#include "tree.h"
24#include "cp-tree.h"
25#include "flags.h"
26
27#define NULL 0
28
29extern tree build_t_desc_overload ();
30
31/* This is the function decl for the (pseudo-builtin) __gc_protect
32 function. Args are (class *value, int index); Returns value. */
33tree gc_protect_fndecl;
34
35/* This is the function decl for the (pseudo-builtin) __gc_unprotect
36 function. Args are (int index); void return. */
37tree gc_unprotect_fndecl;
38
39/* This is the function decl for the (pseudo-builtin) __gc_push
40 function. Args are (int length); void return. */
41tree gc_push_fndecl;
42
43/* This is the function decl for the (pseudo-builtin) __gc_pop
44 function. Args are void; void return. */
45tree gc_pop_fndecl;
46
47/* Special integers that are used to represent bits in gc-safe objects. */
48tree gc_nonobject;
49tree gc_visible;
50tree gc_white;
51tree gc_offwhite;
52tree gc_grey;
53tree gc_black;
54\f
55/* Predicate that returns non-zero if TYPE needs some kind of
56 entry for the GC. Returns zero otherwise. */
57int
58type_needs_gc_entry (type)
59 tree type;
60{
61 tree ttype = type;
62
63 if (! flag_gc || type == error_mark_node)
64 return 0;
65
66 /* Aggregate types need gc entries if any of their members
67 need gc entries. */
68 if (IS_AGGR_TYPE (type))
69 {
70 tree binfos;
71 tree fields = TYPE_FIELDS (type);
72 int i;
73
74 /* We don't care about certain pointers. Pointers
75 to virtual baseclasses are always up front. We also
76 cull out virtual function table pointers because it's
77 easy, and it simplifies the logic.*/
78 while (fields
79 && (DECL_NAME (fields) == NULL_TREE
80 || VFIELD_NAME_P (DECL_NAME (fields))
81 || VBASE_NAME_P (DECL_NAME (fields))
82 || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fields)), "__bits")))
83 fields = TREE_CHAIN (fields);
84
85 while (fields)
86 {
87 if (type_needs_gc_entry (TREE_TYPE (fields)))
88 return 1;
89 fields = TREE_CHAIN (fields);
90 }
91
92 binfos = TYPE_BINFO_BASETYPES (type);
93 if (binfos)
94 for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
95 if (type_needs_gc_entry (BINFO_TYPE (TREE_VEC_ELT (binfos, i))))
96 return 1;
97
98 return 0;
99 }
100
101 while (TREE_CODE (ttype) == ARRAY_TYPE
102 && TREE_CODE (TREE_TYPE (ttype)) == ARRAY_TYPE)
103 ttype = TREE_TYPE (ttype);
104 if ((TREE_CODE (ttype) == POINTER_TYPE
105 || TREE_CODE (ttype) == ARRAY_TYPE
106 || TREE_CODE (ttype) == REFERENCE_TYPE)
107 && IS_AGGR_TYPE (TREE_TYPE (ttype))
108 && CLASSTYPE_DOSSIER (TREE_TYPE (ttype)))
109 return 1;
110
111 return 0;
112}
113
114/* Predicate that returns non-zero iff FROM is safe from the GC.
115
116 If TO is nonzero, it means we know that FROM is being stored
117 in TO, which make make it safe. */
118int
119value_safe_from_gc (to, from)
120 tree to, from;
121{
122 /* First, return non-zero for easy cases: parameters,
123 static variables. */
124 if (TREE_CODE (from) == PARM_DECL
125 || (TREE_CODE (from) == VAR_DECL
126 && TREE_STATIC (from)))
127 return 1;
128
129 /* If something has its address taken, it cannot be
130 in the heap, so it doesn't need to be protected. */
131 if (TREE_CODE (from) == ADDR_EXPR || TREE_REFERENCE_EXPR (from))
132 return 1;
133
134 /* If we are storing into a static variable, then what
135 we store will be safe from the gc. */
136 if (to && TREE_CODE (to) == VAR_DECL
137 && TREE_STATIC (to))
138 return 1;
139
140 /* Now recurse on structure of FROM. */
141 switch (TREE_CODE (from))
142 {
143 case COMPONENT_REF:
144 /* These guys are special, and safe. */
145 if (TREE_CODE (TREE_OPERAND (from, 1)) == FIELD_DECL
146 && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (from, 1)))
147 || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (from, 1)))))
148 return 1;
149 /* fall through... */
150 case NOP_EXPR:
151 case CONVERT_EXPR:
152 case NON_LVALUE_EXPR:
153 case WITH_CLEANUP_EXPR:
154 case SAVE_EXPR:
155 case PREDECREMENT_EXPR:
156 case PREINCREMENT_EXPR:
157 case POSTDECREMENT_EXPR:
158 case POSTINCREMENT_EXPR:
159 if (value_safe_from_gc (to, TREE_OPERAND (from, 0)))
160 return 1;
161 break;
162
163 case VAR_DECL:
164 case PARM_DECL:
165 /* We can safely pass these things as parameters to functions. */
166 if (to == 0)
167 return 1;
168
169 case ARRAY_REF:
170 case INDIRECT_REF:
171 case RESULT_DECL:
172 case OFFSET_REF:
173 case CALL_EXPR:
174 case METHOD_CALL_EXPR:
175 break;
176
177 case COMPOUND_EXPR:
178 case TARGET_EXPR:
179 if (value_safe_from_gc (to, TREE_OPERAND (from, 1)))
180 return 1;
181 break;
182
183 case COND_EXPR:
184 if (value_safe_from_gc (to, TREE_OPERAND (from, 1))
185 && value_safe_from_gc (to, TREE_OPERAND (from, 2)))
186 return 1;
187 break;
188
189 case PLUS_EXPR:
190 case MINUS_EXPR:
191 if ((type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 0)))
192 || value_safe_from_gc (to, TREE_OPERAND (from, 0)))
193 && (type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 1))) == 0
194 || value_safe_from_gc (to, TREE_OPERAND (from, 1))))
195 return 1;
196 break;
197
198 case RTL_EXPR:
199 /* Every time we build an RTL_EXPR in the front-end, we must
200 ensure that everything in it is safe from the garbage collector.
201 ??? This has only been done for `build_new'. */
202 return 1;
203
204 default:
205 my_friendly_abort (41);
206 }
207
208 if (to == 0)
209 return 0;
210
211 /* FROM wasn't safe. But other properties of TO might make it safe. */
212 switch (TREE_CODE (to))
213 {
214 case VAR_DECL:
215 case PARM_DECL:
216 /* We already culled out static VAR_DECLs above. */
217 return 0;
218
219 case COMPONENT_REF:
220 /* These guys are special, and safe. */
221 if (TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL
222 && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (to, 1)))
223 || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (to, 1)))))
224 return 1;
225 /* fall through... */
226
227 case NOP_EXPR:
228 case NON_LVALUE_EXPR:
229 case WITH_CLEANUP_EXPR:
230 case SAVE_EXPR:
231 case PREDECREMENT_EXPR:
232 case PREINCREMENT_EXPR:
233 case POSTDECREMENT_EXPR:
234 case POSTINCREMENT_EXPR:
235 return value_safe_from_gc (TREE_OPERAND (to, 0), from);
236
237 case COMPOUND_EXPR:
238 case TARGET_EXPR:
239 return value_safe_from_gc (TREE_OPERAND (to, 1), from);
240
241 case COND_EXPR:
242 return (value_safe_from_gc (TREE_OPERAND (to, 1), from)
243 && value_safe_from_gc (TREE_OPERAND (to, 2), from));
244
245 case INDIRECT_REF:
246 case ARRAY_REF:
247 /* This used to be 0, but our current restricted model
248 allows this to be 1. We'll never get arrays this way. */
249 return 1;
250
251 default:
252 my_friendly_abort (42);
253 }
254
255 /* Catch-all case is that TO/FROM is not safe. */
256 return 0;
257}
258\f
259/* Function to build a static GC entry for DECL. TYPE is DECL's type.
260
261 For objects of type `class *', this is just an entry in the
262 static vector __PTR_LIST__.
263
264 For objects of type `class[]', this requires building an entry
265 in the static vector __ARR_LIST__.
266
267 For aggregates, this records all fields of type `class *'
268 and `class[]' in the respective lists above. */
269void
270build_static_gc_entry (decl, type)
271 tree decl;
272 tree type;
273{
274 /* Now, figure out what sort of entry to build. */
275 if (TREE_CODE (type) == POINTER_TYPE
276 || TREE_CODE (type) == REFERENCE_TYPE)
277 assemble_gc_entry (IDENTIFIER_POINTER (DECL_NAME (decl)));
278 else if (TREE_CODE (type) == RECORD_TYPE)
279 {
280 tree ref = get_temp_name (build_reference_type (type), 1);
281 DECL_INITIAL (ref) = build1 (ADDR_EXPR, TREE_TYPE (ref), decl);
282 TREE_CONSTANT (DECL_INITIAL (ref)) = 1;
283 finish_decl (ref, DECL_INITIAL (ref), 0, 0);
284 }
285 else
286 {
287 /* Not yet implemented.
288
289 Cons up a static variable that holds address and length info
290 and add that to ___ARR_LIST__. */
291 my_friendly_abort (43);
292 }
293}
294\f
295/* Protect FROM from the GC, assuming FROM is going to be
296 stored into TO. We handle three cases for TO here:
297
298 case 1: TO is a stack variable.
299 case 2: TO is zero (which means it is a parameter).
300 case 3: TO is a return value. */
301
302tree
303protect_value_from_gc (to, from)
304 tree to, from;
305{
306 if (to == 0)
307 {
308 tree cleanup;
309
310 to = get_temp_regvar (TREE_TYPE (from), from);
311
312 /* Convert from integer to list form since we'll use it twice. */
313 DECL_GC_OFFSET (to) = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to));
314 cleanup = build_function_call (gc_unprotect_fndecl,
315 DECL_GC_OFFSET (to));
316
317 if (! expand_decl_cleanup (to, cleanup))
318 {
319 compiler_error ("cannot unprotect parameter in this scope");
320 return error_mark_node;
321 }
322 }
323
324 /* Should never need to protect a value that's headed for static storage. */
325 if (TREE_STATIC (to))
326 my_friendly_abort (44);
327
328 switch (TREE_CODE (to))
329 {
330 case COMPONENT_REF:
331 case INDIRECT_REF:
332 return protect_value_from_gc (TREE_OPERAND (to, 0), from);
333
334 case VAR_DECL:
335 case PARM_DECL:
336 {
337 tree rval;
338 if (DECL_GC_OFFSET (to) == NULL_TREE)
339 {
340 /* Because of a cast or a conversion, we might stick
341 a value into a variable that would not normally
342 have a GC entry. */
343 DECL_GC_OFFSET (to) = size_int (++current_function_obstack_index);
344 }
345
346 if (TREE_CODE (DECL_GC_OFFSET (to)) != TREE_LIST)
347 {
348 DECL_GC_OFFSET (to)
349 = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to));
350 }
351
352 current_function_obstack_usage = 1;
353 rval = build_function_call (gc_protect_fndecl,
354 tree_cons (NULL_TREE, from,
355 DECL_GC_OFFSET (to)));
356 TREE_TYPE (rval) = TREE_TYPE (from);
357 return rval;
358 }
359 }
360
361 /* If we fall through the switch, assume we lost. */
362 my_friendly_abort (45);
363 /* NOTREACHED */
364 return NULL_TREE;
365}
366\f
367/* Given the expression EXP of type `class *', return the head
368 of the object pointed to by EXP. */
369tree
370build_headof (exp)
371 tree exp;
372{
373 tree type = TREE_TYPE (exp);
374 tree vptr, offset;
375
376 if (TREE_CODE (type) != POINTER_TYPE)
377 {
378 error ("`headof' applied to non-pointer type");
379 return error_mark_node;
380 }
381
382 vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp);
383 offset = build_component_ref (build_array_ref (vptr, integer_one_node),
384 get_identifier (VTABLE_DELTA_NAME),
385 NULL_TREE, 0);
386 return build (PLUS_EXPR, class_star_type_node, exp,
387 convert (integer_type_node, offset));
388}
389
390/* Given the expression EXP of type `class *', return the
391 type descriptor for the object pointed to by EXP. */
392tree
393build_classof (exp)
394 tree exp;
395{
396 tree type = TREE_TYPE (exp);
397 tree vptr;
398 tree t_desc_entry;
399
400 if (TREE_CODE (type) != POINTER_TYPE)
401 {
402 error ("`classof' applied to non-pointer type");
403 return error_mark_node;
404 }
405
406 vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp);
407 t_desc_entry = build_component_ref (build_array_ref (vptr, integer_one_node),
408 get_identifier (VTABLE_PFN_NAME),
409 NULL_TREE, 0);
410 TREE_TYPE (t_desc_entry) = TYPE_POINTER_TO (__t_desc_type_node);
411 return t_desc_entry;
412}
413\f
414/* Build and initialize various sorts of descriptors. Every descriptor
415 node has a name associated with it (the name created by mangling).
416 For this reason, we use the identifier as our access to the __*_desc
417 nodes, instead of sticking them directly in the types. Otherwise we
418 would burden all built-in types (and pointer types) with slots that
419 we don't necessarily want to use.
420
421 For each descriptor we build, we build a variable that contains
422 the descriptor's information. When we need this info at runtime,
423 all we need is access to these variables.
424
425 Note: these constructors always return the address of the descriptor
426 info, since that is simplest for their mutual interaction. */
427
428static tree
429build_generic_desc (decl, elems)
430 tree decl;
431 tree elems;
432{
433 tree init = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, elems);
434 TREE_CONSTANT (init) = 1;
435 TREE_STATIC (init) = 1;
436 TREE_READONLY (init) = 1;
437
438 DECL_INITIAL (decl) = init;
439 TREE_STATIC (decl) = 1;
440 layout_decl (decl, 0);
441 finish_decl (decl, init, 0, 0);
442
443 return IDENTIFIER_AS_DESC (DECL_NAME (decl));
444}
445
446/* Build an initializer for a __t_desc node. So that we can take advantage
447 of recursion, we accept NULL for TYPE.
448 DEFINITION is greater than zero iff we must define the type descriptor
449 (as opposed to merely referencing it). 1 means treat according to
450 #pragma interface/#pragma implementation rules. 2 means define as
451 global and public, no matter what. */
452tree
453build_t_desc (type, definition)
454 tree type;
455 int definition;
456{
457 tree tdecl;
458 tree tname, name_string;
459 tree elems, fields;
460 tree parents, vbases, offsets, ivars, methods, target_type;
461 int method_count = 0, field_count = 0;
462
463 if (type == NULL_TREE)
464 return NULL_TREE;
465
466 tname = build_t_desc_overload (type);
467 if (IDENTIFIER_AS_DESC (tname)
468 && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname))))
469 return IDENTIFIER_AS_DESC (tname);
470
471 tdecl = lookup_name (tname, 0);
472 if (tdecl == NULL_TREE)
473 {
474 tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node);
475 DECL_EXTERNAL (tdecl) = 1;
476 TREE_PUBLIC (tdecl) = 1;
477 tdecl = pushdecl_top_level (tdecl);
478 }
479 /* If we previously defined it, return the defined result. */
480 else if (definition && DECL_INITIAL (tdecl))
481 return IDENTIFIER_AS_DESC (tname);
482
483 if (definition)
484 {
485 tree taggr = type;
486 /* Let T* and T& be written only when T is written (if T is an aggr).
487 We do this for const, but not for volatile, since volatile
488 is rare and const is not. */
489 if (!TYPE_VOLATILE (taggr)
490 && (TREE_CODE (taggr) == POINTER_TYPE
491 || TREE_CODE (taggr) == REFERENCE_TYPE)
492 && IS_AGGR_TYPE (TREE_TYPE (taggr)))
493 taggr = TREE_TYPE (taggr);
494
495 /* If we know that we don't need to write out this type's
496 vtable, then don't write out it's dossier. Somebody
497 else will take care of that. */
498 if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr))
499 {
500 if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr))
501 {
502 TREE_PUBLIC (tdecl) = !(CLASSTYPE_INTERFACE_ONLY (taggr)
503 || CLASSTYPE_INTERFACE_UNKNOWN (taggr));
504 TREE_STATIC (tdecl) = 1;
505 DECL_EXTERNAL (tdecl) = 0;
506 }
507 else
508 {
509 if (write_virtuals != 0)
510 TREE_PUBLIC (tdecl) = 1;
511 }
512 }
513 else
514 {
515 DECL_EXTERNAL (tdecl) = 0;
516 TREE_STATIC (tdecl) = 1;
517 TREE_PUBLIC (tdecl) = (definition > 1);
518 }
519 }
520 SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0));
521 if (!definition || DECL_EXTERNAL (tdecl))
522 {
523 /* That's it! */
524 finish_decl (tdecl, 0, 0, 0);
525 return IDENTIFIER_AS_DESC (tname);
526 }
527
528 /* Show that we are defining the t_desc for this type. */
529 DECL_INITIAL (tdecl) = error_mark_node;
530
531 parents = build_tree_list (NULL_TREE, integer_zero_node);
532 vbases = build_tree_list (NULL_TREE, integer_zero_node);
533 offsets = build_tree_list (NULL_TREE, integer_zero_node);
534 methods = NULL_TREE;
535 ivars = NULL_TREE;
536
537 if (TYPE_LANG_SPECIFIC (type))
538 {
539 int i = CLASSTYPE_N_BASECLASSES (type);
540 tree method_vec = CLASSTYPE_METHOD_VEC (type);
541 tree *meth, *end;
542 tree binfos = TYPE_BINFO_BASETYPES (type);
543 tree vb = CLASSTYPE_VBASECLASSES (type);
544
545 while (--i >= 0)
546 parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents);
547
548 while (vb)
549 {
550 vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases);
551 offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets);
552 vb = TREE_CHAIN (vb);
553 }
554
555 if (method_vec)
556 for (meth = TREE_VEC_END (method_vec),
557 end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; )
558 if (*meth)
559 {
560 methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods);
561 method_count++;
562 }
563 }
564
565 if (IS_AGGR_TYPE (type))
566 {
567 for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
568 if (TREE_CODE (fields) == FIELD_DECL
569 || TREE_CODE (fields) == VAR_DECL)
570 {
571 ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars);
572 field_count++;
573 }
574 ivars = nreverse (ivars);
575 }
576
577 parents = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), parents, 0);
578 vbases = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), vbases, 0);
579 offsets = finish_table (0, integer_type_node, offsets, 0);
580 methods = finish_table (0, __m_desc_type_node, methods, 0);
581 ivars = finish_table (0, __i_desc_type_node, ivars, 0);
582 if (TREE_TYPE (type))
583 target_type = build_t_desc (TREE_TYPE (type), definition);
584 else
585 target_type = integer_zero_node;
586
587 name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
588
589 elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
590 tree_cons (NULL_TREE,
591 TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node,
592 /* really should use bitfield initialization here. */
593 tree_cons (NULL_TREE, integer_zero_node,
594 tree_cons (NULL_TREE, target_type,
595 tree_cons (NULL_TREE, build_int_2 (field_count, 2),
596 tree_cons (NULL_TREE, build_int_2 (method_count, 2),
597 tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, ivars, 0),
598 tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, methods, 0),
599 tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0),
600 tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0),
601 build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0))))))))))));
602 return build_generic_desc (tdecl, elems);
603}
604
605/* Build an initializer for a __i_desc node. */
606tree
607build_i_desc (decl)
608 tree decl;
609{
610 tree elems, name_string;
611 tree taggr;
612
613 name_string = DECL_NAME (decl);
614 name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string)));
615
616 /* Now decide whether this ivar should cause it's type to get
617 def'd or ref'd in this file. If the type we are looking at
618 has a proxy definition, we look at the proxy (i.e., a
619 `foo *' is equivalent to a `foo'). */
620 taggr = TREE_TYPE (decl);
621
622 if ((TREE_CODE (taggr) == POINTER_TYPE
623 || TREE_CODE (taggr) == REFERENCE_TYPE)
624 && TYPE_VOLATILE (taggr) == 0)
625 taggr = TREE_TYPE (taggr);
626
627 elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
628 tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl),
629 build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl),
630 ! IS_AGGR_TYPE (taggr)))));
631 taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems);
632 TREE_CONSTANT (taggr) = 1;
633 TREE_STATIC (taggr) = 1;
634 TREE_READONLY (taggr) = 1;
635 return taggr;
636}
637
638/* Build an initializer for a __m_desc node. */
639tree
640build_m_desc (decl)
641 tree decl;
642{
643 tree taggr, elems, name_string;
644 tree parm_count, req_count, vindex, vcontext;
645 tree parms;
646 int p_count, r_count;
647 tree parm_types = NULL_TREE;
648
649 for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0;
650 parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++)
651 {
652 taggr = TREE_VALUE (parms);
653 if ((TREE_CODE (taggr) == POINTER_TYPE
654 || TREE_CODE (taggr) == REFERENCE_TYPE)
655 && TYPE_VOLATILE (taggr) == 0)
656 taggr = TREE_TYPE (taggr);
657
658 parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms),
659 ! IS_AGGR_TYPE (taggr)),
660 parm_types);
661 if (TREE_PURPOSE (parms) == NULL_TREE)
662 r_count++;
663 }
664
665 parm_types = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node),
666 nreverse (parm_types), 0);
667 parm_count = build_int_2 (p_count, 0);
668 req_count = build_int_2 (r_count, 0);
669
670 if (DECL_VINDEX (decl))
671 vindex = DECL_VINDEX (decl);
672 else
673 vindex = integer_zero_node;
674 if (DECL_CONTEXT (decl)
675 && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
676 vcontext = build_t_desc (DECL_CONTEXT (decl), 0);
677 else
678 vcontext = integer_zero_node;
679 name_string = DECL_NAME (decl);
680 if (name_string == NULL)
681 name_string = DECL_ASSEMBLER_NAME (decl);
682 name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string)));
683
684 /* Now decide whether the return type of this mvar
685 should cause it's type to get def'd or ref'd in this file.
686 If the type we are looking at has a proxy definition,
687 we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */
688 taggr = TREE_TYPE (TREE_TYPE (decl));
689
690 if ((TREE_CODE (taggr) == POINTER_TYPE
691 || TREE_CODE (taggr) == REFERENCE_TYPE)
692 && TYPE_VOLATILE (taggr) == 0)
693 taggr = TREE_TYPE (taggr);
694
695 elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
696 tree_cons (NULL_TREE, vindex,
697 tree_cons (NULL_TREE, vcontext,
698 tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)),
699 ! IS_AGGR_TYPE (taggr)),
700 tree_cons (NULL_TREE, build_c_cast (TYPE_POINTER_TO (default_function_type), build_unary_op (ADDR_EXPR, decl, 0)),
701 tree_cons (NULL_TREE, parm_count,
702 tree_cons (NULL_TREE, req_count,
703 build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0)))))))));
704
705 taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems);
706 TREE_CONSTANT (taggr) = 1;
707 TREE_STATIC (taggr) = 1;
708 TREE_READONLY (taggr) = 1;
709 return taggr;
710}
711\f
712/* Conditionally emit code to set up an unwind-protect for the
713 garbage collector. If this function doesn't do anything that involves
714 the garbage collector, then do nothing. Otherwise, call __gc_push
715 at the beginning and __gc_pop at the end.
716
717 NOTE! The __gc_pop function must operate transparently, since
718 it comes where the logical return label lies. This means that
719 at runtime *it* must preserve any return value registers. */
720
721void
722expand_gc_prologue_and_epilogue ()
723{
724 extern tree maybe_gc_cleanup;
725 struct rtx_def *last_parm_insn, *mark;
726 extern struct rtx_def *get_last_insn ();
727 extern struct rtx_def *get_first_nonparm_insn ();
728 extern struct rtx_def *previous_insn ();
729 tree action;
730
731 /* If we didn't need the obstack, don't cons any space. */
732 if (current_function_obstack_index == 0
733 || current_function_obstack_usage == 0)
734 return;
735
736 mark = get_last_insn ();
737 last_parm_insn = get_first_nonparm_insn ();
738 if (last_parm_insn == 0) last_parm_insn = mark;
739 else last_parm_insn = previous_insn (last_parm_insn);
740
741 action = build_function_call (gc_push_fndecl,
742 build_tree_list (NULL_TREE, size_int (++current_function_obstack_index)));
743 expand_expr_stmt (action);
744
745 reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
746
747 /* This will be expanded as a cleanup. */
748 TREE_VALUE (maybe_gc_cleanup)
749 = build_function_call (gc_pop_fndecl, NULL_TREE);
750}
751
752/* Some day we'll use this function as a call-back and clean
753 up all the unnecessary gc dribble that we otherwise create. */
754void
755lang_expand_end_bindings (first, last)
756 struct rtx_def *first, *last;
757{
758}
759\f
760void
761init_gc_processing ()
762{
763 tree parmtypes = hash_tree_chain (class_star_type_node,
764 hash_tree_chain (integer_type_node, NULL_TREE));
765 gc_protect_fndecl = define_function ("__gc_protect",
766 build_function_type (class_star_type_node, parmtypes),
767 NOT_BUILT_IN, 0, 0);
768
769 parmtypes = hash_tree_chain (integer_type_node, NULL_TREE);
770 gc_unprotect_fndecl = define_function ("__gc_unprotect",
771 build_function_type (void_type_node, parmtypes),
772 NOT_BUILT_IN, 0, 0);
773
774 gc_push_fndecl = define_function ("__gc_push",
775 TREE_TYPE (gc_unprotect_fndecl),
776 NOT_BUILT_IN, 0, 0);
777
778 gc_pop_fndecl = define_function ("__gc_pop",
779 build_function_type (void_type_node,
780 void_list_node),
781 NOT_BUILT_IN, 0, 0);
782 gc_nonobject = build_int_2 (0x80000000, 0);
783 gc_visible = build_int_2 (0x40000000, 0);
784 gc_white = integer_zero_node;
785 gc_offwhite = build_int_2 (0x10000000, 0);
786 gc_grey = build_int_2 (0x20000000, 0);
787 gc_black = build_int_2 (0x30000000, 0);
788}