📄 gc.c
字号:
/* Garbage collection primitives for GNU C++. Copyright (C) 1992, 1993, 1994, 1995 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 modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include "tree.h"#include "cp-tree.h"#include "flags.h"#include "output.h"#undef NULL#define NULL 0extern tree define_function ();extern tree build_t_desc_overload ();extern struct obstack *permanent_obstack;/* 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. */inttype_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_RTTI (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. */intvalue_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. */voidbuild_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; cp_finish_decl (ref, DECL_INITIAL (ref), NULL_TREE, 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. */treeprotect_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 (! cp_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. */treebuild_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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -