summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/cc/cc1plus/gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/cc/cc1plus/gc.c')
-rw-r--r--gnu/usr.bin/cc/cc1plus/gc.c988
1 files changed, 988 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/cc1plus/gc.c b/gnu/usr.bin/cc/cc1plus/gc.c
new file mode 100644
index 0000000..9db4d62
--- /dev/null
+++ b/gnu/usr.bin/cc/cc1plus/gc.c
@@ -0,0 +1,988 @@
+/* Garbage collection primitives for GNU C++.
+ Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "flags.h"
+
+#undef NULL
+#define NULL 0
+
+extern tree define_function ();
+extern tree build_t_desc_overload ();
+
+/* This is the function decl for the (pseudo-builtin) __gc_protect
+ function. Args are (class *value, int index); Returns value. */
+tree gc_protect_fndecl;
+
+/* This is the function decl for the (pseudo-builtin) __gc_unprotect
+ function. Args are (int index); void return. */
+tree gc_unprotect_fndecl;
+
+/* This is the function decl for the (pseudo-builtin) __gc_push
+ function. Args are (int length); void return. */
+tree gc_push_fndecl;
+
+/* This is the function decl for the (pseudo-builtin) __gc_pop
+ function. Args are void; void return. */
+tree gc_pop_fndecl;
+
+/* Special integers that are used to represent bits in gc-safe objects. */
+tree gc_nonobject;
+tree gc_visible;
+tree gc_white;
+tree gc_offwhite;
+tree gc_grey;
+tree gc_black;
+
+/* in c-common.c */
+extern tree combine_strings PROTO((tree));
+
+/* Predicate that returns non-zero if TYPE needs some kind of
+ entry for the GC. Returns zero otherwise. */
+int
+type_needs_gc_entry (type)
+ tree type;
+{
+ tree ttype = type;
+
+ if (! flag_gc || type == error_mark_node)
+ return 0;
+
+ /* Aggregate types need gc entries if any of their members
+ need gc entries. */
+ if (IS_AGGR_TYPE (type))
+ {
+ tree binfos;
+ tree fields = TYPE_FIELDS (type);
+ int i;
+
+ /* We don't care about certain pointers. Pointers
+ to virtual baseclasses are always up front. We also
+ cull out virtual function table pointers because it's
+ easy, and it simplifies the logic.*/
+ while (fields
+ && (DECL_NAME (fields) == NULL_TREE
+ || VFIELD_NAME_P (DECL_NAME (fields))
+ || VBASE_NAME_P (DECL_NAME (fields))
+ || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fields)), "__bits")))
+ fields = TREE_CHAIN (fields);
+
+ while (fields)
+ {
+ if (type_needs_gc_entry (TREE_TYPE (fields)))
+ return 1;
+ fields = TREE_CHAIN (fields);
+ }
+
+ binfos = TYPE_BINFO_BASETYPES (type);
+ if (binfos)
+ for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
+ if (type_needs_gc_entry (BINFO_TYPE (TREE_VEC_ELT (binfos, i))))
+ return 1;
+
+ return 0;
+ }
+
+ while (TREE_CODE (ttype) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (ttype)) == ARRAY_TYPE)
+ ttype = TREE_TYPE (ttype);
+ if ((TREE_CODE (ttype) == POINTER_TYPE
+ || TREE_CODE (ttype) == ARRAY_TYPE
+ || TREE_CODE (ttype) == REFERENCE_TYPE)
+ && IS_AGGR_TYPE (TREE_TYPE (ttype))
+ && CLASSTYPE_DOSSIER (TREE_TYPE (ttype)))
+ return 1;
+
+ return 0;
+}
+
+/* Predicate that returns non-zero iff FROM is safe from the GC.
+
+ If TO is nonzero, it means we know that FROM is being stored
+ in TO, which make make it safe. */
+int
+value_safe_from_gc (to, from)
+ tree to, from;
+{
+ /* First, return non-zero for easy cases: parameters,
+ static variables. */
+ if (TREE_CODE (from) == PARM_DECL
+ || (TREE_CODE (from) == VAR_DECL
+ && TREE_STATIC (from)))
+ return 1;
+
+ /* If something has its address taken, it cannot be
+ in the heap, so it doesn't need to be protected. */
+ if (TREE_CODE (from) == ADDR_EXPR || TREE_REFERENCE_EXPR (from))
+ return 1;
+
+ /* If we are storing into a static variable, then what
+ we store will be safe from the gc. */
+ if (to && TREE_CODE (to) == VAR_DECL
+ && TREE_STATIC (to))
+ return 1;
+
+ /* Now recurse on structure of FROM. */
+ switch (TREE_CODE (from))
+ {
+ case COMPONENT_REF:
+ /* These guys are special, and safe. */
+ if (TREE_CODE (TREE_OPERAND (from, 1)) == FIELD_DECL
+ && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (from, 1)))
+ || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (from, 1)))))
+ return 1;
+ /* fall through... */
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ case WITH_CLEANUP_EXPR:
+ case SAVE_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ if (value_safe_from_gc (to, TREE_OPERAND (from, 0)))
+ return 1;
+ break;
+
+ case VAR_DECL:
+ case PARM_DECL:
+ /* We can safely pass these things as parameters to functions. */
+ if (to == 0)
+ return 1;
+
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ case RESULT_DECL:
+ case OFFSET_REF:
+ case CALL_EXPR:
+ case METHOD_CALL_EXPR:
+ break;
+
+ case COMPOUND_EXPR:
+ case TARGET_EXPR:
+ if (value_safe_from_gc (to, TREE_OPERAND (from, 1)))
+ return 1;
+ break;
+
+ case COND_EXPR:
+ if (value_safe_from_gc (to, TREE_OPERAND (from, 1))
+ && value_safe_from_gc (to, TREE_OPERAND (from, 2)))
+ return 1;
+ break;
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ if ((type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 0)))
+ || value_safe_from_gc (to, TREE_OPERAND (from, 0)))
+ && (type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 1))) == 0
+ || value_safe_from_gc (to, TREE_OPERAND (from, 1))))
+ return 1;
+ break;
+
+ case RTL_EXPR:
+ /* Every time we build an RTL_EXPR in the front-end, we must
+ ensure that everything in it is safe from the garbage collector.
+ ??? This has only been done for `build_new'. */
+ return 1;
+
+ default:
+ my_friendly_abort (41);
+ }
+
+ if (to == 0)
+ return 0;
+
+ /* FROM wasn't safe. But other properties of TO might make it safe. */
+ switch (TREE_CODE (to))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ /* We already culled out static VAR_DECLs above. */
+ return 0;
+
+ case COMPONENT_REF:
+ /* These guys are special, and safe. */
+ if (TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL
+ && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (to, 1)))
+ || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (to, 1)))))
+ return 1;
+ /* fall through... */
+
+ case NOP_EXPR:
+ case NON_LVALUE_EXPR:
+ case WITH_CLEANUP_EXPR:
+ case SAVE_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ return value_safe_from_gc (TREE_OPERAND (to, 0), from);
+
+ case COMPOUND_EXPR:
+ case TARGET_EXPR:
+ return value_safe_from_gc (TREE_OPERAND (to, 1), from);
+
+ case COND_EXPR:
+ return (value_safe_from_gc (TREE_OPERAND (to, 1), from)
+ && value_safe_from_gc (TREE_OPERAND (to, 2), from));
+
+ case INDIRECT_REF:
+ case ARRAY_REF:
+ /* This used to be 0, but our current restricted model
+ allows this to be 1. We'll never get arrays this way. */
+ return 1;
+
+ default:
+ my_friendly_abort (42);
+ }
+
+ /* Catch-all case is that TO/FROM is not safe. */
+ return 0;
+}
+
+/* Function to build a static GC entry for DECL. TYPE is DECL's type.
+
+ For objects of type `class *', this is just an entry in the
+ static vector __PTR_LIST__.
+
+ For objects of type `class[]', this requires building an entry
+ in the static vector __ARR_LIST__.
+
+ For aggregates, this records all fields of type `class *'
+ and `class[]' in the respective lists above. */
+void
+build_static_gc_entry (decl, type)
+ tree decl;
+ tree type;
+{
+ /* Now, figure out what sort of entry to build. */
+ if (TREE_CODE (type) == POINTER_TYPE
+ || TREE_CODE (type) == REFERENCE_TYPE)
+ assemble_gc_entry (IDENTIFIER_POINTER (DECL_NAME (decl)));
+ else if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ tree ref = get_temp_name (build_reference_type (type), 1);
+ DECL_INITIAL (ref) = build1 (ADDR_EXPR, TREE_TYPE (ref), decl);
+ TREE_CONSTANT (DECL_INITIAL (ref)) = 1;
+ finish_decl (ref, DECL_INITIAL (ref), 0, 0);
+ }
+ else
+ {
+ /* Not yet implemented.
+
+ Cons up a static variable that holds address and length info
+ and add that to ___ARR_LIST__. */
+ my_friendly_abort (43);
+ }
+}
+
+/* Protect FROM from the GC, assuming FROM is going to be
+ stored into TO. We handle three cases for TO here:
+
+ case 1: TO is a stack variable.
+ case 2: TO is zero (which means it is a parameter).
+ case 3: TO is a return value. */
+
+tree
+protect_value_from_gc (to, from)
+ tree to, from;
+{
+ if (to == 0)
+ {
+ tree cleanup;
+
+ to = get_temp_regvar (TREE_TYPE (from), from);
+
+ /* Convert from integer to list form since we'll use it twice. */
+ DECL_GC_OFFSET (to) = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to));
+ cleanup = build_function_call (gc_unprotect_fndecl,
+ DECL_GC_OFFSET (to));
+
+ if (! expand_decl_cleanup (to, cleanup))
+ {
+ compiler_error ("cannot unprotect parameter in this scope");
+ return error_mark_node;
+ }
+ }
+
+ /* Should never need to protect a value that's headed for static storage. */
+ if (TREE_STATIC (to))
+ my_friendly_abort (44);
+
+ switch (TREE_CODE (to))
+ {
+ case COMPONENT_REF:
+ case INDIRECT_REF:
+ return protect_value_from_gc (TREE_OPERAND (to, 0), from);
+
+ case VAR_DECL:
+ case PARM_DECL:
+ {
+ tree rval;
+ if (DECL_GC_OFFSET (to) == NULL_TREE)
+ {
+ /* Because of a cast or a conversion, we might stick
+ a value into a variable that would not normally
+ have a GC entry. */
+ DECL_GC_OFFSET (to) = size_int (++current_function_obstack_index);
+ }
+
+ if (TREE_CODE (DECL_GC_OFFSET (to)) != TREE_LIST)
+ {
+ DECL_GC_OFFSET (to)
+ = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to));
+ }
+
+ current_function_obstack_usage = 1;
+ rval = build_function_call (gc_protect_fndecl,
+ tree_cons (NULL_TREE, from,
+ DECL_GC_OFFSET (to)));
+ TREE_TYPE (rval) = TREE_TYPE (from);
+ return rval;
+ }
+ }
+
+ /* If we fall through the switch, assume we lost. */
+ my_friendly_abort (45);
+ /* NOTREACHED */
+ return NULL_TREE;
+}
+
+/* Given the expression EXP of type `class *', return the head
+ of the object pointed to by EXP. */
+tree
+build_headof (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (exp);
+ tree vptr, offset;
+
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ error ("`headof' applied to non-pointer type");
+ return error_mark_node;
+ }
+
+ if (flag_vtable_thunks)
+ abort();
+
+ vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp);
+ offset = build_component_ref (build_array_ref (vptr, integer_one_node),
+ get_identifier (VTABLE_DELTA_NAME),
+ NULL_TREE, 0);
+ return build (PLUS_EXPR, class_star_type_node, exp,
+ convert (integer_type_node, offset));
+}
+
+/* Given the expression EXP of type `class *', return the
+ type descriptor for the object pointed to by EXP. */
+tree
+build_classof (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (exp);
+ tree vptr;
+ tree t_desc_entry;
+
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ error ("`classof' applied to non-pointer type");
+ return error_mark_node;
+ }
+
+ vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp);
+ t_desc_entry = build_component_ref (build_array_ref (vptr, integer_one_node),
+ get_identifier (VTABLE_PFN_NAME),
+ NULL_TREE, 0);
+ TREE_TYPE (t_desc_entry) = TYPE_POINTER_TO (__t_desc_type_node);
+ return t_desc_entry;
+}
+
+/* Return the Type_info node associated with the expression EXP. If EXP is
+ a reference to a polymorphic class, return the dynamic type; otherwise
+ return the static type of the expression. */
+tree
+build_typeid (exp)
+ tree exp;
+{
+ tree type;
+
+ if (exp == error_mark_node)
+ return error_mark_node;
+
+ type = TREE_TYPE (exp);
+
+ /* if b is an instance of B, typeid(b) == typeid(B). Do this before
+ reference trickiness. */
+ if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE)
+ return get_typeid (type);
+
+ /* Apply trivial conversion T -> T& for dereferenced ptrs. */
+ if (TREE_CODE (type) == RECORD_TYPE)
+ type = build_reference_type (type);
+
+ /* If exp is a reference to polymorphic type, get the real Type_info. */
+ if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type)))
+ {
+ /* build reference to Type_info from vtable. */
+
+ sorry ("finding Type_info for an object");
+ return error_mark_node;
+ }
+
+ /* otherwise return the Type_info for the static type of the expr. */
+ return get_typeid (type);
+}
+
+/* Return the Type_info object for TYPE, creating it if necessary. */
+tree
+get_typeid (type)
+ tree type;
+{
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ /* Is it useful (and/or correct) to have different typeids for `T &'
+ and `T'? */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ /* build reference to static Type_info */
+#if 1
+ sorry ("finding Type_info for a type");
+ return error_mark_node;
+#else
+ register tree t = TYPE_TINFO (type);
+
+ if (t)
+ return t;
+
+ /* ... */
+
+#endif
+}
+
+/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
+ paper. */
+tree
+build_dynamic_cast (type, expr)
+ tree type, expr;
+{
+ enum tree_code tc = TREE_CODE (type);
+ tree exprtype = TREE_TYPE (expr);
+ enum tree_code ec = TREE_CODE (exprtype);
+ tree retval;
+
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+
+ switch (tc)
+ {
+ case POINTER_TYPE:
+ if (TREE_TYPE (type) == void_type_node)
+ break;
+ /* else fall through */
+ case REFERENCE_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
+ && TYPE_SIZE (TREE_TYPE (type)) != NULL_TREE)
+ break;
+ /* else fall through */
+ default:
+ cp_error ("`%#T' is not a valid type argument for dynamic_cast", type);
+ error ("(must be either pointer or reference to defined class or void *)");
+ return error_mark_node;
+ }
+
+ /* Apply trivial conversion T -> T& for dereferenced ptrs. */
+ if (ec == RECORD_TYPE)
+ {
+ exprtype = build_reference_type (exprtype);
+ ec = REFERENCE_TYPE;
+ }
+
+ /* the TREE_CODE of exprtype must match that of type. */
+ if (ec != tc)
+ {
+ cp_error ("`%E' (of type `%#T') fails to be of %s type", expr, exprtype,
+ tc == POINTER_TYPE ? "pointer" : "reference");
+ return error_mark_node;
+ }
+
+ /* If *type is an unambiguous accessible base class of *exprtype,
+ convert statically. */
+ {
+ int distance;
+ tree path;
+
+ distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
+ &path);
+ if (distance >= 0)
+ return build_vbase_path (PLUS_EXPR, type, expr, path, 0);
+ }
+
+ /* Otherwise *exprtype must be a polymorphic class (have a vtbl). */
+ if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype)))
+ {
+ /* if TYPE is `void *', return pointer to complete object. */
+ if (tc == POINTER_TYPE && TREE_TYPE (type) == void_type_node)
+ {
+ /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */
+ if (TREE_CODE (expr) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
+ return build1 (NOP_EXPR, type, expr);
+
+ sorry ("finding pointer to complete object");
+ return build1 (NOP_EXPR, type, expr);
+ }
+ else
+ {
+ tree retval;
+
+ /* If we got here, we can't convert statically. Therefore,
+ dynamic_cast<D&>(b) (b an object) cannot succeed. */
+ if (ec == REFERENCE_TYPE)
+ {
+ if (TREE_CODE (expr) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE)
+ {
+ cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
+ expr, type);
+ /* cplus_expand_throw (Bad_cast_node); */
+ sorry ("throwing Bad_cast");
+ return error_mark_node;
+ }
+ }
+ /* Ditto for dynamic_cast<D*>(&b). */
+ else if (TREE_CODE (expr) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (TREE_CODE (op) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)
+ {
+ cp_warning ("dynamic_cast of `%E' to `%#T' can never succeed",
+ expr, type);
+ retval = build_int_2 (0, 0);
+ TREE_TYPE (retval) = type;
+ return retval;
+ }
+ }
+ /* Build run-time conversion. */
+ sorry ("run-time type conversion");
+ retval = build_int_2 (0, 0);
+ TREE_TYPE (retval) = type;
+ return retval;
+ }
+ }
+
+ cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'",
+ expr, exprtype, type);
+ return error_mark_node;
+}
+
+/* Build and initialize various sorts of descriptors. Every descriptor
+ node has a name associated with it (the name created by mangling).
+ For this reason, we use the identifier as our access to the __*_desc
+ nodes, instead of sticking them directly in the types. Otherwise we
+ would burden all built-in types (and pointer types) with slots that
+ we don't necessarily want to use.
+
+ For each descriptor we build, we build a variable that contains
+ the descriptor's information. When we need this info at runtime,
+ all we need is access to these variables.
+
+ Note: these constructors always return the address of the descriptor
+ info, since that is simplest for their mutual interaction. */
+
+static tree
+build_generic_desc (decl, elems)
+ tree decl;
+ tree elems;
+{
+ tree init = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, elems);
+ TREE_CONSTANT (init) = 1;
+ TREE_STATIC (init) = 1;
+ TREE_READONLY (init) = 1;
+
+ DECL_INITIAL (decl) = init;
+ TREE_STATIC (decl) = 1;
+ layout_decl (decl, 0);
+ finish_decl (decl, init, 0, 0);
+
+ return IDENTIFIER_AS_DESC (DECL_NAME (decl));
+}
+
+/* Build an initializer for a __t_desc node. So that we can take advantage
+ of recursion, we accept NULL for TYPE.
+ DEFINITION is greater than zero iff we must define the type descriptor
+ (as opposed to merely referencing it). 1 means treat according to
+ #pragma interface/#pragma implementation rules. 2 means define as
+ global and public, no matter what. */
+tree
+build_t_desc (type, definition)
+ tree type;
+ int definition;
+{
+ tree tdecl;
+ tree tname, name_string;
+ tree elems, fields;
+ tree parents, vbases, offsets, ivars, methods, target_type;
+ int method_count = 0, field_count = 0;
+
+ if (type == NULL_TREE)
+ return NULL_TREE;
+
+ tname = build_t_desc_overload (type);
+ if (IDENTIFIER_AS_DESC (tname)
+ && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname))))
+ return IDENTIFIER_AS_DESC (tname);
+
+ tdecl = lookup_name (tname, 0);
+ if (tdecl == NULL_TREE)
+ {
+ tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node);
+ DECL_EXTERNAL (tdecl) = 1;
+ TREE_PUBLIC (tdecl) = 1;
+ tdecl = pushdecl_top_level (tdecl);
+ }
+ /* If we previously defined it, return the defined result. */
+ else if (definition && DECL_INITIAL (tdecl))
+ return IDENTIFIER_AS_DESC (tname);
+
+ if (definition)
+ {
+ tree taggr = type;
+ /* Let T* and T& be written only when T is written (if T is an aggr).
+ We do this for const, but not for volatile, since volatile
+ is rare and const is not. */
+ if (!TYPE_VOLATILE (taggr)
+ && (TREE_CODE (taggr) == POINTER_TYPE
+ || TREE_CODE (taggr) == REFERENCE_TYPE)
+ && IS_AGGR_TYPE (TREE_TYPE (taggr)))
+ taggr = TREE_TYPE (taggr);
+
+ /* If we know that we don't need to write out this type's
+ vtable, then don't write out it's dossier. Somebody
+ else will take care of that. */
+ if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr))
+ {
+ if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr))
+ {
+ TREE_PUBLIC (tdecl) = ! CLASSTYPE_INTERFACE_ONLY (taggr)
+ && CLASSTYPE_INTERFACE_KNOWN (taggr);
+ TREE_STATIC (tdecl) = 1;
+ DECL_EXTERNAL (tdecl) = 0;
+ }
+ else
+ {
+ if (write_virtuals != 0)
+ TREE_PUBLIC (tdecl) = 1;
+ }
+ }
+ else
+ {
+ DECL_EXTERNAL (tdecl) = 0;
+ TREE_STATIC (tdecl) = 1;
+ TREE_PUBLIC (tdecl) = (definition > 1);
+ }
+ }
+ SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0));
+ if (!definition || DECL_EXTERNAL (tdecl))
+ {
+ /* That's it! */
+ finish_decl (tdecl, 0, 0, 0);
+ return IDENTIFIER_AS_DESC (tname);
+ }
+
+ /* Show that we are defining the t_desc for this type. */
+ DECL_INITIAL (tdecl) = error_mark_node;
+
+ parents = build_tree_list (NULL_TREE, integer_zero_node);
+ vbases = build_tree_list (NULL_TREE, integer_zero_node);
+ offsets = build_tree_list (NULL_TREE, integer_zero_node);
+ methods = NULL_TREE;
+ ivars = NULL_TREE;
+
+ if (TYPE_LANG_SPECIFIC (type))
+ {
+ int i = CLASSTYPE_N_BASECLASSES (type);
+ tree method_vec = CLASSTYPE_METHOD_VEC (type);
+ tree *meth, *end;
+ tree binfos = TYPE_BINFO_BASETYPES (type);
+ tree vb = CLASSTYPE_VBASECLASSES (type);
+
+ while (--i >= 0)
+ parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents);
+
+ while (vb)
+ {
+ vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases);
+ offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets);
+ vb = TREE_CHAIN (vb);
+ }
+
+ if (method_vec)
+ for (meth = TREE_VEC_END (method_vec),
+ end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; )
+ if (*meth)
+ {
+ methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods);
+ method_count++;
+ }
+ }
+
+ if (IS_AGGR_TYPE (type))
+ {
+ for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+ if (TREE_CODE (fields) == FIELD_DECL
+ || TREE_CODE (fields) == VAR_DECL)
+ {
+ ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars);
+ field_count++;
+ }
+ ivars = nreverse (ivars);
+ }
+
+ parents = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), parents, 0);
+ vbases = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), vbases, 0);
+ offsets = finish_table (0, integer_type_node, offsets, 0);
+ if (methods == NULL_TREE)
+ methods = null_pointer_node;
+ else
+ methods = build_unary_op (ADDR_EXPR,
+ finish_table (0, __m_desc_type_node, methods, 0),
+ 0);
+ if (ivars == NULL_TREE)
+ ivars = null_pointer_node;
+ else
+ ivars = build_unary_op (ADDR_EXPR,
+ finish_table (0, __i_desc_type_node, ivars, 0),
+ 0);
+ if (TREE_TYPE (type))
+ target_type = build_t_desc (TREE_TYPE (type), definition);
+ else
+ target_type = integer_zero_node;
+
+ name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
+
+ elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
+ tree_cons (NULL_TREE,
+ TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node,
+ /* really should use bitfield initialization here. */
+ tree_cons (NULL_TREE, integer_zero_node,
+ tree_cons (NULL_TREE, target_type,
+ tree_cons (NULL_TREE, build_int_2 (field_count, 2),
+ tree_cons (NULL_TREE, build_int_2 (method_count, 2),
+ tree_cons (NULL_TREE, ivars,
+ tree_cons (NULL_TREE, methods,
+ tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0),
+ tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0),
+ build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0))))))))))));
+ return build_generic_desc (tdecl, elems);
+}
+
+/* Build an initializer for a __i_desc node. */
+tree
+build_i_desc (decl)
+ tree decl;
+{
+ tree elems, name_string;
+ tree taggr;
+
+ name_string = DECL_NAME (decl);
+ name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string)));
+
+ /* Now decide whether this ivar should cause it's type to get
+ def'd or ref'd in this file. If the type we are looking at
+ has a proxy definition, we look at the proxy (i.e., a
+ `foo *' is equivalent to a `foo'). */
+ taggr = TREE_TYPE (decl);
+
+ if ((TREE_CODE (taggr) == POINTER_TYPE
+ || TREE_CODE (taggr) == REFERENCE_TYPE)
+ && TYPE_VOLATILE (taggr) == 0)
+ taggr = TREE_TYPE (taggr);
+
+ elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
+ tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl),
+ build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl),
+ ! IS_AGGR_TYPE (taggr)))));
+ taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems);
+ TREE_CONSTANT (taggr) = 1;
+ TREE_STATIC (taggr) = 1;
+ TREE_READONLY (taggr) = 1;
+ return taggr;
+}
+
+/* Build an initializer for a __m_desc node. */
+tree
+build_m_desc (decl)
+ tree decl;
+{
+ tree taggr, elems, name_string;
+ tree parm_count, req_count, vindex, vcontext;
+ tree parms;
+ int p_count, r_count;
+ tree parm_types = NULL_TREE;
+
+ for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0;
+ parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++)
+ {
+ taggr = TREE_VALUE (parms);
+ if ((TREE_CODE (taggr) == POINTER_TYPE
+ || TREE_CODE (taggr) == REFERENCE_TYPE)
+ && TYPE_VOLATILE (taggr) == 0)
+ taggr = TREE_TYPE (taggr);
+
+ parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms),
+ ! IS_AGGR_TYPE (taggr)),
+ parm_types);
+ if (TREE_PURPOSE (parms) == NULL_TREE)
+ r_count++;
+ }
+
+ parm_types = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node),
+ nreverse (parm_types), 0);
+ parm_count = build_int_2 (p_count, 0);
+ req_count = build_int_2 (r_count, 0);
+
+ if (DECL_VINDEX (decl))
+ vindex = DECL_VINDEX (decl);
+ else
+ vindex = integer_zero_node;
+ if (DECL_CONTEXT (decl)
+ && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
+ vcontext = build_t_desc (DECL_CONTEXT (decl), 0);
+ else
+ vcontext = integer_zero_node;
+ name_string = DECL_NAME (decl);
+ if (name_string == NULL)
+ name_string = DECL_ASSEMBLER_NAME (decl);
+ name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string)));
+
+ /* Now decide whether the return type of this mvar
+ should cause it's type to get def'd or ref'd in this file.
+ If the type we are looking at has a proxy definition,
+ we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */
+ taggr = TREE_TYPE (TREE_TYPE (decl));
+
+ if ((TREE_CODE (taggr) == POINTER_TYPE
+ || TREE_CODE (taggr) == REFERENCE_TYPE)
+ && TYPE_VOLATILE (taggr) == 0)
+ taggr = TREE_TYPE (taggr);
+
+ elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
+ tree_cons (NULL_TREE, vindex,
+ tree_cons (NULL_TREE, vcontext,
+ tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)),
+ ! IS_AGGR_TYPE (taggr)),
+ tree_cons (NULL_TREE, build_c_cast (TYPE_POINTER_TO (default_function_type), build_unary_op (ADDR_EXPR, decl, 0)),
+ tree_cons (NULL_TREE, parm_count,
+ tree_cons (NULL_TREE, req_count,
+ build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0)))))))));
+
+ taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems);
+ TREE_CONSTANT (taggr) = 1;
+ TREE_STATIC (taggr) = 1;
+ TREE_READONLY (taggr) = 1;
+ return taggr;
+}
+
+/* Conditionally emit code to set up an unwind-protect for the
+ garbage collector. If this function doesn't do anything that involves
+ the garbage collector, then do nothing. Otherwise, call __gc_push
+ at the beginning and __gc_pop at the end.
+
+ NOTE! The __gc_pop function must operate transparently, since
+ it comes where the logical return label lies. This means that
+ at runtime *it* must preserve any return value registers. */
+
+void
+expand_gc_prologue_and_epilogue ()
+{
+ extern tree maybe_gc_cleanup;
+ struct rtx_def *last_parm_insn, *mark;
+ extern struct rtx_def *get_last_insn ();
+ extern struct rtx_def *get_first_nonparm_insn ();
+ extern struct rtx_def *previous_insn ();
+ tree action;
+
+ /* If we didn't need the obstack, don't cons any space. */
+ if (current_function_obstack_index == 0
+ || current_function_obstack_usage == 0)
+ return;
+
+ mark = get_last_insn ();
+ last_parm_insn = get_first_nonparm_insn ();
+ if (last_parm_insn == 0) last_parm_insn = mark;
+ else last_parm_insn = previous_insn (last_parm_insn);
+
+ action = build_function_call (gc_push_fndecl,
+ build_tree_list (NULL_TREE, size_int (++current_function_obstack_index)));
+ expand_expr_stmt (action);
+
+ reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
+
+ /* This will be expanded as a cleanup. */
+ TREE_VALUE (maybe_gc_cleanup)
+ = build_function_call (gc_pop_fndecl, NULL_TREE);
+}
+
+/* Some day we'll use this function as a call-back and clean
+ up all the unnecessary gc dribble that we otherwise create. */
+void
+lang_expand_end_bindings (first, last)
+ struct rtx_def *first, *last;
+{
+}
+
+void
+init_gc_processing ()
+{
+ tree parmtypes = hash_tree_chain (class_star_type_node,
+ hash_tree_chain (integer_type_node, NULL_TREE));
+ gc_protect_fndecl = define_function ("__gc_protect",
+ build_function_type (class_star_type_node, parmtypes),
+ NOT_BUILT_IN, 0, 0);
+
+ parmtypes = hash_tree_chain (integer_type_node, NULL_TREE);
+ gc_unprotect_fndecl = define_function ("__gc_unprotect",
+ build_function_type (void_type_node, parmtypes),
+ NOT_BUILT_IN, 0, 0);
+
+ gc_push_fndecl = define_function ("__gc_push",
+ TREE_TYPE (gc_unprotect_fndecl),
+ NOT_BUILT_IN, 0, 0);
+
+ gc_pop_fndecl = define_function ("__gc_pop",
+ build_function_type (void_type_node,
+ void_list_node),
+ NOT_BUILT_IN, 0, 0);
+ gc_nonobject = build_int_2 (0x80000000, 0);
+ gc_visible = build_int_2 (0x40000000, 0);
+ gc_white = integer_zero_node;
+ gc_offwhite = build_int_2 (0x10000000, 0);
+ gc_grey = build_int_2 (0x20000000, 0);
+ gc_black = build_int_2 (0x30000000, 0);
+}
OpenPOWER on IntegriCloud