From patchwork Sat Jan 6 00:26:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 25244 Received: (qmail 5574 invoked by alias); 6 Jan 2018 00:26:30 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 5339 invoked by uid 89); 6 Jan 2018 00:26:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=bypassing, sk:discard, complicating, destruction X-HELO: gateway20.websitewelcome.com Received: from gateway20.websitewelcome.com (HELO gateway20.websitewelcome.com) (192.185.69.18) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 06 Jan 2018 00:26:26 +0000 Received: from cm16.websitewelcome.com (cm16.websitewelcome.com [100.42.49.19]) by gateway20.websitewelcome.com (Postfix) with ESMTP id B7CC7400F3640 for ; Fri, 5 Jan 2018 18:26:24 -0600 (CST) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with SMTP id XcJceEpJrODN4XcJceEYe9; Fri, 05 Jan 2018 18:26:24 -0600 Received: from 71-218-90-63.hlrn.qwest.net ([71.218.90.63]:39986 helo=pokyo.Home) by box5379.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1eXcJc-0035k1-Fl; Fri, 05 Jan 2018 18:26:24 -0600 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [RFA 3/6] Allocate dwarf2_cu with new Date: Fri, 5 Jan 2018 17:26:18 -0700 Message-Id: <20180106002621.21099-4-tom@tromey.com> In-Reply-To: <20180106002621.21099-1-tom@tromey.com> References: <20180106002621.21099-1-tom@tromey.com> X-BWhitelist: no X-Source-L: No X-Exim-ID: 1eXcJc-0035k1-Fl X-Source-Sender: 71-218-90-63.hlrn.qwest.net (pokyo.Home) [71.218.90.63]:39986 X-Source-Auth: tom+tromey.com X-Email-Count: 4 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes This changes dwarf2_cu to be allocated with new, and fixes up the users. 2018-01-05 Tom Tromey * dwarf2read.c (struct dwarf2_cu): Add constructor, destructor. : Declare method. (~auto_free_abbrev_table): Update. (init_tu_and_read_dwo_dies): Use unique_ptr. Remove cleanups. (init_cutu_and_read_dies): Likewise. (init_cutu_and_read_dies_no_follow): Update. (dwarf2_free_abbrev_table): Remove. (dwarf2_cu::dwarf2_cu): New. Rename from init_one_comp_unit. (dwarf2_cu::~dwarf2_cu): New. (dwarf2_cu::free_abbrev_table): New method. (free_heap_comp_unit, free_stack_comp_unit): Remove. (age_cached_comp_units, free_one_cached_comp_unit): Use delete. --- gdb/ChangeLog | 15 ++++ gdb/dwarf2read.c | 247 +++++++++++++++++++++---------------------------------- 2 files changed, 107 insertions(+), 155 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 339a4e728a..04000eacae 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,20 @@ 2018-01-05 Tom Tromey + * dwarf2read.c (struct dwarf2_cu): Add constructor, destructor. + : Declare method. + (~auto_free_abbrev_table): Update. + (init_tu_and_read_dwo_dies): Use unique_ptr. Remove cleanups. + (init_cutu_and_read_dies): Likewise. + (init_cutu_and_read_dies_no_follow): Update. + (dwarf2_free_abbrev_table): Remove. + (dwarf2_cu::dwarf2_cu): New. Rename from init_one_comp_unit. + (dwarf2_cu::~dwarf2_cu): New. + (dwarf2_cu::free_abbrev_table): New method. + (free_heap_comp_unit, free_stack_comp_unit): Remove. + (age_cached_comp_units, free_one_cached_comp_unit): Use delete. + +2018-01-05 Tom Tromey + * dwarf2read.c (class auto_free_abbrev_table): New. (struct abbrev_table): Add constructor, destructor. : Declare methods. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 7fd68c54fa..400080b208 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -639,23 +639,31 @@ DEF_VEC_O (delayed_method_info); /* Internal state when decoding a particular compilation unit. */ struct dwarf2_cu { + dwarf2_cu (struct dwarf2_per_cu_data *per_cu); + ~dwarf2_cu (); + + DISABLE_COPY_AND_ASSIGN (dwarf2_cu); + + void free_abbrev_table (); + + /* The objfile containing this compilation unit. */ struct objfile *objfile; /* The header of the compilation unit. */ - struct comp_unit_head header; + struct comp_unit_head header {}; /* Base address of this compilation unit. */ - CORE_ADDR base_address; + CORE_ADDR base_address = 0; /* Non-zero if base_address has been set. */ - int base_known; + int base_known = 0; /* The language we are debugging. */ - enum language language; - const struct language_defn *language_defn; + enum language language = language_unknown; + const struct language_defn *language_defn = nullptr; - const char *producer; + const char *producer = nullptr; /* The generic symbol table building routines have separate lists for file scope symbols and all all other scopes (local scopes). So @@ -666,60 +674,60 @@ struct dwarf2_cu first local scope, and all other local scopes as nested local scopes, and worked fine. Check to see if we really need to distinguish these in buildsym.c. */ - struct pending **list_in_scope; + struct pending **list_in_scope = nullptr; /* The abbrev table for this CU. Normally this points to the abbrev table in the objfile. But if DWO_UNIT is non-NULL this is the abbrev table in the DWO file. */ - struct abbrev_table *abbrev_table; + struct abbrev_table *abbrev_table = nullptr; /* Hash table holding all the loaded partial DIEs with partial_die->offset.SECT_OFF as hash. */ - htab_t partial_dies; + htab_t partial_dies = nullptr; /* Storage for things with the same lifetime as this read-in compilation unit, including partial DIEs. */ - struct obstack comp_unit_obstack; + auto_obstack comp_unit_obstack; /* When multiple dwarf2_cu structures are living in memory, this field chains them all together, so that they can be released efficiently. We will probably also want a generation counter so that most-recently-used compilation units are cached... */ - struct dwarf2_per_cu_data *read_in_chain; + struct dwarf2_per_cu_data *read_in_chain = nullptr; /* Backlink to our per_cu entry. */ struct dwarf2_per_cu_data *per_cu; /* How many compilation units ago was this CU last referenced? */ - int last_used; + int last_used = 0; /* A hash table of DIE cu_offset for following references with die_info->offset.sect_off as hash. */ - htab_t die_hash; + htab_t die_hash = nullptr; /* Full DIEs if read in. */ - struct die_info *dies; + struct die_info *dies = nullptr; /* A set of pointers to dwarf2_per_cu_data objects for compilation units referenced by this one. Only set during full symbol processing; partial symbol tables do not have dependencies. */ - htab_t dependencies; + htab_t dependencies = nullptr; /* Header data from the line table, during full symbol processing. */ - struct line_header *line_header; + struct line_header *line_header = nullptr; /* Non-NULL if LINE_HEADER is owned by this DWARF_CU. Otherwise, it's owned by dwarf2_per_objfile::line_header_hash. If non-NULL, this is the DW_TAG_compile_unit die for this CU. We'll hold on to the line header as long as this DIE is being processed. See process_die_scope. */ - die_info *line_header_die_owner; + die_info *line_header_die_owner = nullptr; /* A list of methods which need to have physnames computed after all type information has been read. */ - VEC (delayed_method_info) *method_list; + VEC (delayed_method_info) *method_list = nullptr; /* To be copied to symtab->call_site_htab. */ - htab_t call_site_htab; + htab_t call_site_htab = nullptr; /* Non-NULL if this CU came from a DWO file. There is an invariant here that is important to remember: @@ -730,12 +738,12 @@ struct dwarf2_cu is moot), or there is and either we're not going to read it (in which case this is NULL) or there is and we are reading it (in which case this is non-NULL). */ - struct dwo_unit *dwo_unit; + struct dwo_unit *dwo_unit = nullptr; /* The DW_AT_addr_base attribute if present, zero otherwise (zero is a valid value though). Note this value comes from the Fission stub CU/TU's DIE. */ - ULONGEST addr_base; + ULONGEST addr_base = 0; /* The DW_AT_ranges_base attribute if present, zero otherwise (zero is a valid value though). @@ -747,7 +755,7 @@ struct dwarf2_cu DW_AT_ranges appeared in the DW_TAG_compile_unit of DWO DIEs: then DW_AT_ranges_base *would* have to be applied, and we'd have to care whether the DW_AT_ranges attribute came from the skeleton or DWO. */ - ULONGEST ranges_base; + ULONGEST ranges_base = 0; /* Mark used when releasing cached dies. */ unsigned int mark : 1; @@ -774,8 +782,6 @@ struct dwarf2_cu unsigned int processing_has_namespace_info : 1; }; -static void dwarf2_free_abbrev_table (struct dwarf2_cu *); - /* Free an abbrev table on destruction. */ class auto_free_abbrev_table @@ -788,7 +794,7 @@ public: ~auto_free_abbrev_table () { - dwarf2_free_abbrev_table (m_cu); + m_cu->free_abbrev_table (); } private: @@ -2141,8 +2147,6 @@ static const gdb_byte *skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr, struct abbrev_info *abbrev); -static void free_stack_comp_unit (void *); - static hashval_t partial_die_hash (const void *item); static int partial_die_eq (const void *item_lhs, const void *item_rhs); @@ -2150,15 +2154,10 @@ static int partial_die_eq (const void *item_lhs, const void *item_rhs); static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit (sect_offset sect_off, unsigned int offset_in_dwz, struct objfile *objfile); -static void init_one_comp_unit (struct dwarf2_cu *cu, - struct dwarf2_per_cu_data *per_cu); - static void prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die, enum language pretend_language); -static void free_heap_comp_unit (void *); - static void free_cached_comp_units (void *); static void age_cached_comp_units (void); @@ -2442,7 +2441,7 @@ dwarf2_per_objfile::free_cached_comp_units () { dwarf2_per_cu_data *next_cu = per_cu->cu->read_in_chain; - free_heap_comp_unit (per_cu->cu); + delete per_cu->cu; *last_chain = next_cu; per_cu = next_cu; } @@ -7543,7 +7542,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu, } else { - dwarf2_free_abbrev_table (cu); + cu->free_abbrev_table (); dwarf2_read_abbrevs (cu, dwo_abbrev_section); /* Leave any existing abbrev table cleanup as is. */ } @@ -7649,12 +7648,7 @@ lookup_dwo_unit (struct dwarf2_per_cu_data *this_cu, /* Subroutine of init_cutu_and_read_dies to simplify it. See it for a description of the parameters. - Read a TU directly from a DWO file, bypassing the stub. - - Note: This function could be a little bit simpler if we shared cleanups - with our caller, init_cutu_and_read_dies. That's generally a fragile thing - to do, so we keep this function self-contained. Or we could move this - into our caller, but it's complex enough already. */ + Read a TU directly from a DWO file, bypassing the stub. */ static void init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu, @@ -7663,8 +7657,8 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu, void *data) { struct dwarf2_cu *cu; + std::unique_ptr new_cu; struct signatured_type *sig_type; - struct cleanup *cleanups, *free_cu_cleanup = NULL; struct die_reader_specs reader; const gdb_byte *info_ptr; struct die_info *comp_unit_die; @@ -7676,8 +7670,6 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu, sig_type = (struct signatured_type *) this_cu; gdb_assert (sig_type->dwo_unit != NULL); - cleanups = make_cleanup (null_cleanup, NULL); - if (use_existing_cu && this_cu->cu != NULL) { gdb_assert (this_cu->cu->dwo_unit == sig_type->dwo_unit); @@ -7689,10 +7681,8 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu, { /* If !use_existing_cu, this_cu->cu must be NULL. */ gdb_assert (this_cu->cu == NULL); - cu = XNEW (struct dwarf2_cu); - init_one_comp_unit (cu, this_cu); - /* If an error occurs while loading, release our storage. */ - free_cu_cleanup = make_cleanup (free_heap_comp_unit, cu); + new_cu.reset (new dwarf2_cu (this_cu)); + cu = new_cu.get (); } /* A future optimization, if needed, would be to use an existing @@ -7709,7 +7699,6 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu, &abbrev_table) == 0) { /* Dummy die. */ - do_cleanups (cleanups); return; } @@ -7720,23 +7709,19 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu, but the alternative is making the latter more complex. This function is only for the special case of using DWO files directly: no point in overly complicating the general case just to handle this. */ - if (free_cu_cleanup != NULL) + if (new_cu != NULL && keep) { - if (keep) - { - /* We've successfully allocated this compilation unit. Let our - caller clean it up when finished with it. */ - discard_cleanups (free_cu_cleanup); + /* We've successfully allocated this compilation unit. Let our + caller clean it up when finished with it. We have to + manually free the abbrev table. */ + cu->free_abbrev_table (); - /* Link this CU into read_in_chain. */ - this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; - dwarf2_per_objfile->read_in_chain = this_cu; - } - else - do_cleanups (free_cu_cleanup); + /* Link this CU into read_in_chain. */ + this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; + dwarf2_per_objfile->read_in_chain = this_cu; + /* The chain owns it now. */ + new_cu.release (); } - - do_cleanups (cleanups); } /* Initialize a CU (or TU) and read its DIEs. @@ -7771,7 +7756,6 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, struct die_info *comp_unit_die; int has_children; struct attribute *attr; - struct cleanup *cleanups, *free_cu_cleanup = NULL; struct signatured_type *sig_type = NULL; struct dwarf2_section_info *abbrev_section; /* Non-zero if CU currently points to a DWO file and we need to @@ -7799,8 +7783,6 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, return; } - cleanups = make_cleanup (null_cleanup, NULL); - /* This is cheap if the section is already read in. */ dwarf2_read_section (objfile, section); @@ -7808,6 +7790,7 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, abbrev_section = get_abbrev_section_for_cu (this_cu); + std::unique_ptr new_cu; if (use_existing_cu && this_cu->cu != NULL) { cu = this_cu->cu; @@ -7824,10 +7807,8 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, { /* If !use_existing_cu, this_cu->cu must be NULL. */ gdb_assert (this_cu->cu == NULL); - cu = XNEW (struct dwarf2_cu); - init_one_comp_unit (cu, this_cu); - /* If an error occurs while loading, release our storage. */ - free_cu_cleanup = make_cleanup (free_heap_comp_unit, cu); + new_cu.reset (new dwarf2_cu (this_cu)); + cu = new_cu.get (); } /* Get the header. */ @@ -7879,7 +7860,6 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, if (info_ptr >= begin_info_ptr + this_cu->length || peek_abbrev_code (abfd, info_ptr) == 0) { - do_cleanups (cleanups); return; } @@ -7902,7 +7882,7 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, } else if (rereading_dwo_cu) { - dwarf2_free_abbrev_table (cu); + cu->free_abbrev_table (); dwarf2_read_abbrevs (cu, abbrev_section); } @@ -7939,7 +7919,6 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, &abbrev_table_freer_2) == 0) { /* Dummy die. */ - do_cleanups (cleanups); return; } comp_unit_die = dwo_comp_unit_die; @@ -7958,23 +7937,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data); /* Done, clean up. */ - if (free_cu_cleanup != NULL) + if (new_cu != NULL && keep) { - if (keep) - { - /* We've successfully allocated this compilation unit. Let our - caller clean it up when finished with it. */ - discard_cleanups (free_cu_cleanup); - - /* Link this CU into read_in_chain. */ - this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; - dwarf2_per_objfile->read_in_chain = this_cu; - } - else - do_cleanups (free_cu_cleanup); + /* Link this CU into read_in_chain. */ + this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain; + dwarf2_per_objfile->read_in_chain = this_cu; + /* The chain owns it now. */ + new_cu.release (); } - - do_cleanups (cleanups); } /* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name if present. @@ -8003,10 +7973,8 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu, struct dwarf2_section_info *section = this_cu->section; bfd *abfd = get_section_bfd_owner (section); struct dwarf2_section_info *abbrev_section; - struct dwarf2_cu cu; const gdb_byte *begin_info_ptr, *info_ptr; struct die_reader_specs reader; - struct cleanup *cleanups; struct die_info *comp_unit_die; int has_children; @@ -8024,9 +7992,7 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu, /* This is cheap if the section is already read in. */ dwarf2_read_section (objfile, section); - init_one_comp_unit (&cu, this_cu); - - cleanups = make_cleanup (free_stack_comp_unit, &cu); + struct dwarf2_cu cu (this_cu); begin_info_ptr = info_ptr = section->buffer + to_underlying (this_cu->sect_off); info_ptr = read_and_check_comp_unit_head (&cu.header, section, @@ -8041,7 +8007,6 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu, if (info_ptr >= begin_info_ptr + this_cu->length || peek_abbrev_code (abfd, info_ptr) == 0) { - do_cleanups (cleanups); return; } @@ -8052,8 +8017,6 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu, info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, &has_children); die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data); - - do_cleanups (cleanups); } /* Read a CU/TU, except that this does not look for DW_AT_GNU_dwo_name and @@ -18098,20 +18061,6 @@ dwarf2_read_abbrevs (struct dwarf2_cu *cu, = (abbrev_table_read_table (abbrev_section, cu->header.abbrev_sect_off) .release ()); } - -/* Release the memory used by the abbrev table for a compilation unit. */ - -static void -dwarf2_free_abbrev_table (struct dwarf2_cu *cu) -{ - if (cu->abbrev_table != NULL) - { - delete cu->abbrev_table; - /* Set this to NULL so that we SEGV if we try to read it later, - and also because free_comp_unit verifies this is NULL. */ - cu->abbrev_table = NULL; - } -} /* Returns nonzero if TAG represents a type that we might generate a partial symbol for. */ @@ -24949,14 +24898,39 @@ dwarf2_find_containing_comp_unit (sect_offset sect_off, /* Initialize dwarf2_cu CU, owned by PER_CU. */ -static void -init_one_comp_unit (struct dwarf2_cu *cu, struct dwarf2_per_cu_data *per_cu) +dwarf2_cu::dwarf2_cu (struct dwarf2_per_cu_data *per_cu_) + : objfile (per_cu_->objfile), + per_cu (per_cu_), + mark (0), + has_loclist (0), + checked_producer (0), + producer_is_gxx_lt_4_6 (0), + producer_is_gcc_lt_4_3 (0), + producer_is_icc_lt_14 (0), + processing_has_namespace_info (0) { - memset (cu, 0, sizeof (*cu)); - per_cu->cu = cu; - cu->per_cu = per_cu; - cu->objfile = per_cu->objfile; - obstack_init (&cu->comp_unit_obstack); + per_cu->cu = this; +} + +/* Destroy a dwarf2_cu. */ + +dwarf2_cu::~dwarf2_cu () +{ + per_cu->cu = NULL; +} + +/* Free just the abbrev table. */ + +void +dwarf2_cu::free_abbrev_table () +{ + if (abbrev_table != NULL) + { + delete abbrev_table; + /* Set this to NULL so that we SEGV if we try to read it later, + and also because free_comp_unit verifies this is NULL. */ + abbrev_table = NULL; + } } /* Initialize basic fields of dwarf_cu CU according to DIE COMP_UNIT_DIE. */ @@ -24980,43 +24954,6 @@ prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die, cu->producer = dwarf2_string_attr (comp_unit_die, DW_AT_producer, cu); } -/* Release one cached compilation unit, CU. We unlink it from the tree - of compilation units, but we don't remove it from the read_in_chain; - the caller is responsible for that. - NOTE: DATA is a void * because this function is also used as a - cleanup routine. */ - -static void -free_heap_comp_unit (void *data) -{ - struct dwarf2_cu *cu = (struct dwarf2_cu *) data; - - gdb_assert (cu->per_cu != NULL); - cu->per_cu->cu = NULL; - cu->per_cu = NULL; - - obstack_free (&cu->comp_unit_obstack, NULL); - - xfree (cu); -} - -/* This cleanup function is passed the address of a dwarf2_cu on the stack - when we're finished with it. We can't free the pointer itself, but be - sure to unlink it from the cache. Also release any associated storage. */ - -static void -free_stack_comp_unit (void *data) -{ - struct dwarf2_cu *cu = (struct dwarf2_cu *) data; - - gdb_assert (cu->per_cu != NULL); - cu->per_cu->cu = NULL; - cu->per_cu = NULL; - - obstack_free (&cu->comp_unit_obstack, NULL); - cu->partial_dies = NULL; -} - /* Free all cached compilation units. */ static void @@ -25053,7 +24990,7 @@ age_cached_comp_units (void) if (!per_cu->cu->mark) { - free_heap_comp_unit (per_cu->cu); + delete per_cu->cu; *last_chain = next_cu; } else @@ -25080,7 +25017,7 @@ free_one_cached_comp_unit (struct dwarf2_per_cu_data *target_per_cu) if (per_cu == target_per_cu) { - free_heap_comp_unit (per_cu->cu); + delete per_cu->cu; per_cu->cu = NULL; *last_chain = next_cu; break;