home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
cp-gc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
25KB
|
789 lines
/* Garbage collection primitives for GNU C++.
Copyright (C) 1992 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"
#define NULL 0
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;
/* 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);
T