This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH]: Use vector for access check stack
- From: Nathan Sidwell <nathan at codesourcery dot com>
- To: Mark Mitchell <mark at codesourcery dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Mon, 28 Jun 2004 12:47:27 +0100
- Subject: [C++ PATCH]: Use vector for access check stack
- Organization: CodeSourcery LLC
Mark,
this patch reduces the memory the access checking stack uses. In addition
to using a vector, we use a simple counter when access checking is off. Your
implementation of pop_to_parent was being overly conservative wrt the garbage
collector -- that cannot run in the middle of a function without also
seeing local variables.
built & tested on i686-pc-linux-gnu, ok?
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
nathan@codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk
2004-06-28 Nathan Sidwell <nathan@codesourcery.com>
* cp-tree.h (struct deferred_access): Move to ...
* semantics.c (struct deferred_access): ... here. Adjust.
(deferred_access_stack): Make a VEC(deferred_access),
(deferred_access_free_list): Remove.
(deferred_access_no_check): New.
(push_deferring_access_checks, resume_deferring_access_checks,
stop_deferring_access_checks, pop_deferring_access_checks,
get_deferred_access_checks, pop_to_parent_deferring_access_checks,
perform_deferred_access_checks, perform_or_defer_access_check): Adjust.
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.992
diff -c -3 -p -r1.992 cp-tree.h
*** cp/cp-tree.h 28 Jun 2004 11:07:19 -0000 1.992
--- cp/cp-tree.h 28 Jun 2004 11:36:36 -0000
*************** extern GTY(()) tree integer_three_node;
*** 3102,3133 ****
function, two inside the body of a function in a local class, etc.) */
extern int function_depth;
- typedef struct deferred_access GTY(())
- {
- /* A TREE_LIST representing name-lookups for which we have deferred
- checking access controls. We cannot check the accessibility of
- names used in a decl-specifier-seq until we know what is being
- declared because code like:
-
- class A {
- class B {};
- B* f();
- }
-
- A::B* A::f() { return 0; }
-
- is valid, even though `A::B' is not generally accessible.
-
- The TREE_PURPOSE of each node is the scope used to qualify the
- name being looked up; the TREE_VALUE is the DECL to which the
- name was resolved. */
- tree deferred_access_checks;
- /* The current mode of access checks. */
- enum deferring_kind deferring_access_checks_kind;
- /* The next deferred access data in stack or linked-list. */
- struct deferred_access *next;
- } deferred_access;
-
/* in pt.c */
/* These values are used for the `STRICT' parameter to type_unification and
--- 3102,3107 ----
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.412
diff -c -3 -p -r1.412 semantics.c
*** cp/semantics.c 28 Jun 2004 10:41:19 -0000 1.412
--- cp/semantics.c 28 Jun 2004 11:37:42 -0000
***************
*** 44,49 ****
--- 44,50 ----
#include "diagnostic.h"
#include "cgraph.h"
#include "tree-iterator.h"
+ #include "vec.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
*************** static tree finalize_nrv_r (tree *, int
*** 111,119 ****
In case of parsing error, we simply call `pop_deferring_access_checks'
without `perform_deferred_access_checks'. */
/* Data for deferred access checking. */
! static GTY(()) deferred_access *deferred_access_stack;
! static GTY(()) deferred_access *deferred_access_free_list;
/* Save the current deferred access states and start deferred
access checking iff DEFER_P is true. */
--- 112,147 ----
In case of parsing error, we simply call `pop_deferring_access_checks'
without `perform_deferred_access_checks'. */
+ typedef struct deferred_access GTY(())
+ {
+ /* A TREE_LIST representing name-lookups for which we have deferred
+ checking access controls. We cannot check the accessibility of
+ names used in a decl-specifier-seq until we know what is being
+ declared because code like:
+
+ class A {
+ class B {};
+ B* f();
+ }
+
+ A::B* A::f() { return 0; }
+
+ is valid, even though `A::B' is not generally accessible.
+
+ The TREE_PURPOSE of each node is the scope used to qualify the
+ name being looked up; the TREE_VALUE is the DECL to which the
+ name was resolved. */
+ tree deferred_access_checks;
+
+ /* The current mode of access checks. */
+ enum deferring_kind deferring_access_checks_kind;
+
+ } deferred_access;
+ DEF_VEC_O (deferred_access);
+
/* Data for deferred access checking. */
! static GTY(()) VEC (deferred_access) *deferred_access_stack;
! static GTY(()) unsigned deferred_access_no_check;
/* Save the current deferred access states and start deferred
access checking iff DEFER_P is true. */
*************** static GTY(()) deferred_access *deferred
*** 121,147 ****
void
push_deferring_access_checks (deferring_kind deferring)
{
- deferred_access *d;
-
/* For context like template instantiation, access checking
disabling applies to all nested context. */
! if (deferred_access_stack
! && deferred_access_stack->deferring_access_checks_kind == dk_no_check)
! deferring = dk_no_check;
!
! /* Recycle previously used free store if available. */
! if (deferred_access_free_list)
! {
! d = deferred_access_free_list;
! deferred_access_free_list = d->next;
! }
else
! d = ggc_alloc (sizeof (deferred_access));
! d->next = deferred_access_stack;
! d->deferred_access_checks = NULL_TREE;
! d->deferring_access_checks_kind = deferring;
! deferred_access_stack = d;
}
/* Resume deferring access checks again after we stopped doing
--- 149,166 ----
void
push_deferring_access_checks (deferring_kind deferring)
{
/* For context like template instantiation, access checking
disabling applies to all nested context. */
! if (deferred_access_no_check || deferring == dk_no_check)
! deferred_access_no_check++;
else
! {
! deferred_access *ptr;
! ptr = VEC_safe_push (deferred_access, deferred_access_stack, NULL);
! ptr->deferred_access_checks = NULL_TREE;
! ptr->deferring_access_checks_kind = deferring;
! }
}
/* Resume deferring access checks again after we stopped doing
*************** push_deferring_access_checks (deferring_
*** 150,157 ****
void
resume_deferring_access_checks (void)
{
! if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
! deferred_access_stack->deferring_access_checks_kind = dk_deferred;
}
/* Stop deferring access checks. */
--- 169,177 ----
void
resume_deferring_access_checks (void)
{
! if (!deferred_access_no_check)
! VEC_last (deferred_access, deferred_access_stack)
! ->deferring_access_checks_kind = dk_deferred;
}
/* Stop deferring access checks. */
*************** resume_deferring_access_checks (void)
*** 159,166 ****
void
stop_deferring_access_checks (void)
{
! if (deferred_access_stack->deferring_access_checks_kind == dk_deferred)
! deferred_access_stack->deferring_access_checks_kind = dk_no_deferred;
}
/* Discard the current deferred access checks and restore the
--- 179,187 ----
void
stop_deferring_access_checks (void)
{
! if (!deferred_access_no_check)
! VEC_last (deferred_access, deferred_access_stack)
! ->deferring_access_checks_kind = dk_no_deferred;
}
/* Discard the current deferred access checks and restore the
*************** stop_deferring_access_checks (void)
*** 169,183 ****
void
pop_deferring_access_checks (void)
{
! deferred_access *d = deferred_access_stack;
! deferred_access_stack = d->next;
!
! /* Remove references to access checks TREE_LIST. */
! d->deferred_access_checks = NULL_TREE;
!
! /* Store in free list for later use. */
! d->next = deferred_access_free_list;
! deferred_access_free_list = d;
}
/* Returns a TREE_LIST representing the deferred checks.
--- 190,199 ----
void
pop_deferring_access_checks (void)
{
! if (deferred_access_no_check)
! deferred_access_no_check--;
! else
! VEC_pop (deferred_access, deferred_access_stack);
}
/* Returns a TREE_LIST representing the deferred checks.
*************** pop_deferring_access_checks (void)
*** 188,194 ****
tree
get_deferred_access_checks (void)
{
! return deferred_access_stack->deferred_access_checks;
}
/* Take current deferred checks and combine with the
--- 204,214 ----
tree
get_deferred_access_checks (void)
{
! if (deferred_access_no_check)
! return NULL;
! else
! return (VEC_last (deferred_access, deferred_access_stack)
! ->deferred_access_checks);
}
/* Take current deferred checks and combine with the
*************** get_deferred_access_checks (void)
*** 198,224 ****
void
pop_to_parent_deferring_access_checks (void)
{
! tree deferred_check = get_deferred_access_checks ();
! deferred_access *d1 = deferred_access_stack;
! deferred_access *d2 = deferred_access_stack->next;
! deferred_access *d3 = deferred_access_stack->next->next;
!
! /* Temporary swap the order of the top two states, just to make
! sure the garbage collector will not reclaim the memory during
! processing below. */
! deferred_access_stack = d2;
! d2->next = d1;
! d1->next = d3;
!
! for ( ; deferred_check; deferred_check = TREE_CHAIN (deferred_check))
! /* Perform deferred check if required. */
! perform_or_defer_access_check (TREE_PURPOSE (deferred_check),
! TREE_VALUE (deferred_check));
!
! deferred_access_stack = d1;
! d1->next = d2;
! d2->next = d3;
! pop_deferring_access_checks ();
}
/* Perform the deferred access checks.
--- 218,265 ----
void
pop_to_parent_deferring_access_checks (void)
{
! if (deferred_access_no_check)
! deferred_access_no_check--;
! else
! {
! tree checks;
! deferred_access *ptr;
!
! checks = (VEC_last (deferred_access, deferred_access_stack)
! ->deferred_access_checks);
!
! VEC_pop (deferred_access, deferred_access_stack);
! ptr = VEC_last (deferred_access, deferred_access_stack);
! if (ptr->deferring_access_checks_kind == dk_no_deferred)
! {
! /* Check access. */
! for (; checks; checks = TREE_CHAIN (checks))
! enforce_access (TREE_PURPOSE (checks),
! TREE_VALUE (checks));
! }
! else
! {
! /* Merge with parent. */
! tree next;
! tree original = ptr->deferred_access_checks;
!
! for (; checks; checks = next)
! {
! tree probe;
!
! next = TREE_CHAIN (checks);
!
! for (probe = original; probe; probe = TREE_CHAIN (probe))
! if (TREE_VALUE (probe) == TREE_VALUE (checks)
! && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
! goto found;
! /* Insert into parent's checks. */
! TREE_CHAIN (checks) = ptr->deferred_access_checks;
! ptr->deferred_access_checks = checks;
! found:;
! }
! }
! }
}
/* Perform the deferred access checks.
*************** void
*** 241,247 ****
perform_deferred_access_checks (void)
{
tree deferred_check;
! for (deferred_check = deferred_access_stack->deferred_access_checks;
deferred_check;
deferred_check = TREE_CHAIN (deferred_check))
/* Check access. */
--- 282,290 ----
perform_deferred_access_checks (void)
{
tree deferred_check;
!
! for (deferred_check = (VEC_last (deferred_access, deferred_access_stack)
! ->deferred_access_checks);
deferred_check;
deferred_check = TREE_CHAIN (deferred_check))
/* Check access. */
*************** void
*** 256,285 ****
perform_or_defer_access_check (tree binfo, tree decl)
{
tree check;
! /* Exit if we are in a context that no access checking is performed. */
! if (deferred_access_stack->deferring_access_checks_kind == dk_no_check)
return;
my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
/* If we are not supposed to defer access checks, just check now. */
! if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
{
enforce_access (binfo, decl);
return;
}
/* See if we are already going to perform this check. */
! for (check = deferred_access_stack->deferred_access_checks;
check;
check = TREE_CHAIN (check))
if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
return;
/* If not, record the check. */
! deferred_access_stack->deferred_access_checks
! = tree_cons (binfo, decl,
! deferred_access_stack->deferred_access_checks);
}
/* Returns nonzero if the current statement is a full expression,
--- 299,331 ----
perform_or_defer_access_check (tree binfo, tree decl)
{
tree check;
+ deferred_access *ptr;
! /* Exit if we are in a context that no access checking is performed.
! */
! if (deferred_access_no_check)
return;
my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
+ ptr = VEC_last (deferred_access, deferred_access_stack);
+
/* If we are not supposed to defer access checks, just check now. */
! if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
enforce_access (binfo, decl);
return;
}
/* See if we are already going to perform this check. */
! for (check = ptr->deferred_access_checks;
check;
check = TREE_CHAIN (check))
if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
return;
/* If not, record the check. */
! ptr->deferred_access_checks
! = tree_cons (binfo, decl, ptr->deferred_access_checks);
}
/* Returns nonzero if the current statement is a full expression,