From f1382e4aefcbfd83c8cd12c71e2a6bf48a9a06c4 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 21 Feb 2022 16:01:24 -0600 Subject: [PATCH] Fix memory leak in targets lists. This changes the pointer type used everywhere for _targets/TARGETS to a unique_ptr to manage the ownership correctly. Thus removing the memory leaks resulting therein. --- src/engine/builtins.cpp | 8 +-- src/engine/command.cpp | 5 +- src/engine/command.h | 3 +- src/engine/compile.cpp | 15 +++--- src/engine/make.cpp | 77 ++++++++++++--------------- src/engine/make1.cpp | 79 ++++++++++++++-------------- src/engine/mem.h | 112 ++++++++++++++++++++++++++++------------ src/engine/rules.cpp | 74 ++++++++++++-------------- src/engine/rules.h | 45 ++++++++++------ 9 files changed, 228 insertions(+), 190 deletions(-) diff --git a/src/engine/builtins.cpp b/src/engine/builtins.cpp index 86706a65b..54745bd3c 100644 --- a/src/engine/builtins.cpp +++ b/src/engine/builtins.cpp @@ -563,7 +563,7 @@ LIST * builtin_depends( FRAME * frame, int flags ) if ( flags ) target_include_many( t, sources ); else - t->depends = targetlist( t->depends, sources ); + targetlist( t->depends, sources ); } /* Enter reverse links */ @@ -577,11 +577,11 @@ LIST * builtin_depends( FRAME * frame, int flags ) LISTITER t_iter = list_begin( targets ); LISTITER const t_end = list_end( targets ); for ( ; t_iter != t_end; t_iter = list_next( t_iter ) ) - s->dependants = targetentry( s->dependants, bindtarget( + targetentry( s->dependants, bindtarget( list_item( t_iter ) )->includes ); } else - s->dependants = targetlist( s->dependants, targets ); + targetlist( s->dependants, targets ); } return L0; @@ -604,7 +604,7 @@ LIST * builtin_rebuilds( FRAME * frame, int flags ) for ( ; iter != end; iter = list_next( iter ) ) { TARGET * const t = bindtarget( list_item( iter ) ); - t->rebuilds = targetlist( t->rebuilds, rebuilds ); + targetlist( t->rebuilds, rebuilds ); } return L0; } diff --git a/src/engine/command.cpp b/src/engine/command.cpp index c0c103242..75837d49d 100644 --- a/src/engine/command.cpp +++ b/src/engine/command.cpp @@ -60,7 +60,7 @@ void cmdlist_free( CMDLIST * l ) CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell ) { - CMD * cmd = (CMD *)BJAM_MALLOC( sizeof( CMD ) ); + CMD * cmd = b2::jam::make_ptr(); FRAME frame[ 1 ]; assert( cmd ); @@ -101,8 +101,7 @@ void cmd_free( CMD * cmd ) lol_free( &cmd->args ); list_free( cmd->shell ); string_free( cmd->buf ); - freetargets( cmd->unlock ); - BJAM_FREE( (void *)cmd ); + b2::jam::free_ptr( cmd ); } diff --git a/src/engine/command.h b/src/engine/command.h index 23ab775a1..9163d91ac 100644 --- a/src/engine/command.h +++ b/src/engine/command.h @@ -48,6 +48,7 @@ #include "config.h" #include "lists.h" +#include "mem.h" #include "rules.h" #include "jam_strings.h" @@ -86,7 +87,7 @@ struct _cmd int noop; /* no-op commands should be faked instead of executed */ int asynccnt; /* number of outstanding dependencies */ targets_ptr lock; /* semaphores that are required by this cmd. */ - targets_ptr unlock; /* semaphores that are released when this cmd finishes. */ + targets_uptr unlock; /* semaphores that are released when this cmd finishes. */ char status; /* the command status */ }; diff --git a/src/engine/compile.cpp b/src/engine/compile.cpp index e1c4564fd..75299bc9d 100644 --- a/src/engine/compile.cpp +++ b/src/engine/compile.cpp @@ -110,12 +110,11 @@ LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * frame ) targets_ptr t; /* The action is associated with this instance of this rule. */ - ACTION * const action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) ); - memset( (char *)action, '\0', sizeof( *action ) ); + ACTION * const action = b2::jam::make_ptr(); action->rule = rule; - action->targets = targetlist( (targets_ptr)0, lol_get( frame->args, 0 ) ); - action->sources = targetlist( (targets_ptr)0, lol_get( frame->args, 1 ) ); + action->targets.reset(); targetlist( action->targets, lol_get( frame->args, 0 ) ); + action->sources.reset(); targetlist( action->sources, lol_get( frame->args, 1 ) ); action->refs = 1; /* If we have a group of targets all being built using the same action @@ -126,15 +125,15 @@ LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * frame ) if ( action->targets ) { TARGET * const t0 = action->targets->target; - for ( t = action->targets->next; t; t = t->next ) + for ( t = action->targets->next.get(); t; t = t->next.get() ) { - t->target->rebuilds = targetentry( t->target->rebuilds, t0 ); - t0->rebuilds = targetentry( t0->rebuilds, t->target ); + targetentry( t->target->rebuilds, t0 ); + targetentry( t0->rebuilds, t->target ); } } /* Append this action to the actions of each target. */ - for ( t = action->targets; t; t = t->next ) + for ( t = action->targets.get(); t; t = t->next.get() ) t->target->actions = actionlist( t->target->actions, action ); action_free( action ); diff --git a/src/engine/make.cpp b/src/engine/make.cpp index e6bbc9756..5d3764035 100644 --- a/src/engine/make.cpp +++ b/src/engine/make.cpp @@ -54,7 +54,7 @@ # define max(a,b) ((a)>(b)?(a):(b)) #endif -static targets_ptr make0sort( targets_ptr c ); +static targets_uptr make0sort( targets_uptr c ); #ifdef OPT_GRAPH_DEBUG_EXT static void dependGraphOutput( TARGET * t, int32_t depth ); @@ -174,7 +174,7 @@ static void update_dependants( TARGET * t ) { targets_ptr q; - for ( q = t->dependants; q; q = q->next ) + for ( q = t->dependants.get(); q; q = q->next.get() ) { TARGET * p = q->target; char fate0 = p->fate; @@ -211,7 +211,7 @@ static void update_dependants( TARGET * t ) static void force_rebuilds( TARGET * t ) { targets_ptr d; - for ( d = t->rebuilds; d; d = d->next ) + for ( d = t->rebuilds.get(); d; d = d->next.get() ) { TARGET * r = d->target; @@ -250,7 +250,7 @@ int32_t make0rescan( TARGET * t, TARGET * rescanning ) return 0; t->rescanning = rescanning; - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) { TARGET * dependency = c->target; /* Always start at the root of each new strongly connected component. */ @@ -265,7 +265,7 @@ int32_t make0rescan( TARGET * t, TARGET * rescanning ) if ( result && t->scc_root == NULL ) { t->scc_root = rescanning; - rescanning->depends = targetentry( rescanning->depends, t ); + targetentry( rescanning->depends, t ); } return result; } @@ -408,7 +408,7 @@ void make0 */ /* Step 3a: Recursively make0() dependencies. */ - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) { int32_t const internal = t->flags & T_FLAG_INTERNAL; @@ -442,20 +442,20 @@ void make0 /* Step 3c: Add dependencies' includes to our direct dependencies. */ { - targets_ptr incs = 0; - for ( c = t->depends; c; c = c->next ) + targets_uptr incs; + for ( c = t->depends.get(); c; c = c->next.get() ) if ( c->target->includes ) - incs = targetentry( incs, c->target->includes ); - t->depends = targetchain( t->depends, incs ); + targetentry( incs, c->target->includes ); + t->depends = targetchain( std::move(t->depends), std::move(incs) ); } if ( located_target ) - t->depends = targetentry( t->depends, located_target ); + targetentry( t->depends, located_target ); /* Step 3d: Detect cycles. */ { int32_t cycle_depth = depth; - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) { TARGET * scc_root = target_scc( c->target ); if ( scc_root->fate == T_FATE_MAKING && @@ -479,7 +479,7 @@ void make0 timestamp_clear( &last ); timestamp_clear( &leaf ); fate = T_FATE_STABLE; - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) { /* If we are in a different strongly connected component, pull * timestamps from the root. @@ -700,7 +700,7 @@ void make0 targets_ptr c; for ( a = t->actions; a; a = a->next ) { - for ( c = a->action->targets; c; c = c->next ) + for ( c = a->action->targets.get(); c; c = c->next.get() ) { if ( c->target->fate == T_FATE_INIT ) { @@ -721,7 +721,7 @@ void make0 */ if ( globs.newestfirst ) - t->depends = make0sort( t->depends ); + t->depends = make0sort( std::move(t->depends) ); /* * Step 6: A little harmless tabulating for tracing purposes. @@ -862,7 +862,7 @@ static void dependGraphOutput( TARGET * t, int32_t depth ) out_printf( "\n" ); } - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) { out_printf( " %s : Depends on %s (%s)", spaces( depth ), target_name( c->target ), target_fate[ (int32_t)c->target->fate ] ); @@ -871,7 +871,7 @@ static void dependGraphOutput( TARGET * t, int32_t depth ) out_printf( "\n" ); } - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) dependGraphOutput( c->target, depth + 1 ); } #endif @@ -880,42 +880,31 @@ static void dependGraphOutput( TARGET * t, int32_t depth ) /* * make0sort() - reorder TARGETS chain by their time (newest to oldest). * - * We walk chain, taking each item and inserting it on the sorted result, with - * newest items at the front. This involves updating each of the TARGETS' - * c->next and c->tail. Note that we make c->tail a valid prev pointer for every - * entry. Normally, it is only valid at the head, where prev == tail. Note also - * that while tail is a loop, next ends at the end of the chain. + * This sorts in-place by swapping the target pointers in the chain in a + * rather terrible n-square/2 algorithm. */ -static targets_ptr make0sort( targets_ptr chain ) +static targets_uptr make0sort( targets_uptr chain ) { PROFILE_ENTER( MAKE_MAKE0SORT ); - targets_ptr result = 0; - - /* Walk the current target list. */ - while ( chain ) + // The current tail we put the next newest item. + for ( targets_ptr front = chain.get(); front ; front = front->next.get() ) { - targets_ptr c = chain; - targets_ptr s = result; - - chain = chain->next; - - /* Find point s in result for c. */ - while ( s && timestamp_cmp( &s->target->time, &c->target->time ) > 0 ) - s = s->next; - - /* Insert c in front of s (might be 0). */ - c->next = s; /* good even if s = 0 */ - if ( result == s ) result = c; /* new head of chain? */ - if ( !s ) s = result; /* wrap to ensure a next */ - if ( result != c ) s->tail->next = c; /* not head? be prev's next */ - c->tail = s->tail; /* take on next's prev */ - s->tail = c; /* make next's prev us */ + // Find the maximum time, i.e. most recent in the rest of the chain. + targets_ptr newest = front->next.get(); + for ( targets_ptr rest = newest; rest ; rest = rest->next.get()) + { + if ( timestamp_cmp( &newest->target->time, &rest->target->time ) > 0 ) + newest = rest; + } + // Sort it to the front if needed. + if ( front != newest ) + std::swap( front->target, newest->target ); } PROFILE_EXIT( MAKE_MAKE0SORT ); - return result; + return chain; } diff --git a/src/engine/make1.cpp b/src/engine/make1.cpp index d51d712c2..9f744b4cb 100644 --- a/src/engine/make1.cpp +++ b/src/engine/make1.cpp @@ -60,15 +60,15 @@ #endif static CMD * make1cmds ( TARGET * ); -static LIST * make1list ( LIST *, targets_ptr, int32_t flags ); +static LIST * make1list ( LIST *, const targets_uptr &, int32_t flags ); static SETTINGS * make1settings ( struct module_t *, LIST * vars ); static void make1bind ( TARGET * ); static void push_cmds( CMDLIST * cmds, int32_t status ); static int32_t cmd_sem_lock( TARGET * t ); static void cmd_sem_unlock( TARGET * t ); -static int32_t targets_contains( targets_ptr l, TARGET * t ); -static int32_t targets_equal( targets_ptr l1, targets_ptr l2 ); +static bool targets_contains( const targets_uptr & l, TARGET * t ); +static bool targets_equal( const targets_uptr & l1, const targets_uptr & l2 ); /* Ugly static - it is too hard to carry it through the callbacks. */ @@ -307,7 +307,7 @@ static void make1a( state * const pState ) TARGET * const parent_scc = target_scc( pState->parent ); if ( t != parent_scc ) { - t->parents = targetentry( t->parents, parent_scc ); + targetentry( t->parents, parent_scc ); ++parent_scc->asynccnt; } } @@ -345,7 +345,7 @@ static void make1a( state * const pState ) { stack temp_stack = { NULL }; targets_ptr c; - for ( c = t->depends; c && !quit; c = c->next ) + for ( c = t->depends.get(); c && !quit; c = c->next.get() ) push_state( &temp_stack, c->target, t, T_STATE_MAKE1A ); push_stack_on_stack( &state_stack, &temp_stack ); } @@ -398,7 +398,7 @@ static void make1b( state * const pState ) if ( !globs.noexec ) { targets_ptr c; - for ( c = t->depends; c; c = c->next ) + for ( c = t->depends.get(); c; c = c->next.get() ) if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) ) { @@ -683,9 +683,8 @@ static void make1c( state const * const pState ) * cleaned up correctly. */ t->includes->includes = saved_includes; - for ( c = t->dependants; c; c = c->next ) - c->target->depends = targetentry( c->target->depends, - t->includes ); + for ( c = t->dependants.get(); c; c = c->next.get() ) + targetentry( c->target->depends, t->includes ); /* Will be processed below. */ additional_includes = t->includes; } @@ -696,7 +695,7 @@ static void make1c( state const * const pState ) } if ( additional_includes ) - for ( c = t->parents; c; c = c->next ) + for ( c = t->parents.get(); c; c = c->next.get() ) push_state( &temp_stack, additional_includes, c->target, T_STATE_MAKE1A ); @@ -704,19 +703,18 @@ static void make1c( state const * const pState ) { TARGET * const scc_root = target_scc( t ); assert( scc_root->progress < T_MAKE_DONE ); - for ( c = t->parents; c; c = c->next ) + for ( c = t->parents.get(); c; c = c->next.get() ) { if ( target_scc( c->target ) == scc_root ) push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B ); else - scc_root->parents = targetentry( scc_root->parents, - c->target ); + targetentry( scc_root->parents, c->target ); } } else { - for ( c = t->parents; c; c = c->next ) + for ( c = t->parents.get(); c; c = c->next.get() ) push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B ); } @@ -1173,7 +1171,7 @@ static CMD * make1cmds( TARGET * t ) int32_t start = 0; int32_t chunk = length; int32_t cmd_count = 0; - targets_ptr semaphores = NULL; + targets_uptr semaphores; targets_ptr targets_iter; int32_t unique_targets; do @@ -1264,7 +1262,7 @@ static CMD * make1cmds( TARGET * t ) a0->action->last_cmd = last_cmd; unique_targets = 0; - for ( targets_iter = a0->action->targets; targets_iter; targets_iter = targets_iter->next ) + for ( targets_iter = a0->action->targets.get(); targets_iter; targets_iter = targets_iter->next.get() ) { if ( targets_contains( targets_iter->next, targets_iter->target ) ) continue; @@ -1279,17 +1277,17 @@ static CMD * make1cmds( TARGET * t ) #if OPT_SEMAPHORE /* Collect semaphores */ - for ( targets_iter = a0->action->targets; targets_iter; targets_iter = targets_iter->next ) + for ( targets_iter = a0->action->targets.get(); targets_iter; targets_iter = targets_iter->next.get() ) { TARGET * sem = targets_iter->target->semaphore; if ( sem ) { if ( ! targets_contains( semaphores, sem ) ) - semaphores = targetentry( semaphores, sem ); + targetentry( semaphores, sem ); } } - ( ( CMD * )a0->action->first_cmd )->lock = semaphores; - ( ( CMD * )a0->action->last_cmd )->unlock = semaphores; + ( ( CMD * )a0->action->first_cmd )->lock = semaphores.get(); + ( ( CMD * )a0->action->last_cmd )->unlock = std::move(semaphores); #endif } @@ -1316,9 +1314,10 @@ static CMD * make1cmds( TARGET * t ) * make1list() - turn a list of targets into a LIST, for $(<) and $(>) */ -static LIST * make1list( LIST * l, targets_ptr targets, int32_t flags ) +static LIST * make1list( LIST * l, const targets_uptr & ts, int32_t flags ) { - for ( ; targets; targets = targets->next ) + targets_ptr targets = ts.get(); + for ( ; targets; targets = targets->next.get() ) { TARGET * t = targets->target; @@ -1419,24 +1418,27 @@ static void make1bind( TARGET * t ) } -static int32_t targets_contains( targets_ptr l, TARGET * t ) +static bool targets_contains( const targets_uptr & ts, TARGET * t ) { - for ( ; l; l = l->next ) + targets_ptr l = ts.get(); + for ( ; l; l = l->next.get() ) { if ( t == l->target ) { - return 1; + return true; } } - return 0; + return false; } -static int32_t targets_equal( targets_ptr l1, targets_ptr l2 ) +static bool targets_equal( const targets_uptr & ts1, const targets_uptr & ts2 ) { - for ( ; l1 && l2; l1 = l1->next, l2 = l2->next ) + targets_ptr l1 = ts1.get(); + targets_ptr l2 = ts2.get(); + for ( ; l1 && l2; l1 = l1->next.get(), l2 = l2->next.get() ) { if ( l1->target != l2->target ) - return 0; + return false; } return !l1 && !l2; } @@ -1451,19 +1453,19 @@ static int32_t cmd_sem_lock( TARGET * t ) /* Check whether all the semaphores required for updating * this target are free. */ - for ( iter = cmd->lock; iter; iter = iter->next ) + for ( iter = cmd->lock; iter; iter = iter->next.get() ) { if ( iter->target->asynccnt > 0 ) { if ( DEBUG_EXECCMD ) out_printf( "SEM: %s is busy, delaying launch of %s\n", object_str( iter->target->name ), object_str( t->name ) ); - iter->target->parents = targetentry( iter->target->parents, t ); + targetentry( iter->target->parents, t ); return 0; } } /* Lock the semaphores. */ - for ( iter = cmd->lock; iter; iter = iter->next ) + for ( iter = cmd->lock; iter; iter = iter->next.get() ) { ++iter->target->asynccnt; if ( DEBUG_EXECCMD ) @@ -1483,7 +1485,7 @@ static void cmd_sem_unlock( TARGET * t ) CMD * cmd = ( CMD * )t->cmds; targets_ptr iter; /* Release the semaphores. */ - for ( iter = cmd->unlock; iter; iter = iter->next ) + for ( iter = cmd->unlock.get(); iter; iter = iter->next.get() ) { if ( DEBUG_EXECCMD ) out_printf( "SEM: %s is now free\n", object_str( @@ -1491,19 +1493,14 @@ static void cmd_sem_unlock( TARGET * t ) --iter->target->asynccnt; assert( iter->target->asynccnt <= 0 ); } - for ( iter = cmd->unlock; iter; iter = iter->next ) + for ( iter = cmd->unlock.get(); iter; iter = iter->next.get() ) { /* Find a waiting target that's ready */ while ( iter->target->parents ) { - targets_ptr first = iter->target->parents; - TARGET * t1 = first->target; + TARGET * t1 = iter->target->parents->target; - /* Pop the first waiting CMD */ - if ( first->next ) - first->next->tail = first->tail; - iter->target->parents = first->next; - BJAM_FREE( first ); + iter->target->parents = targets_pop(std::move(iter->target->parents)); if ( cmd_sem_lock( t1 ) ) { diff --git a/src/engine/mem.h b/src/engine/mem.h index 590d80ab9..bf41cd05e 100644 --- a/src/engine/mem.h +++ b/src/engine/mem.h @@ -1,5 +1,5 @@ /* - * Copyright 2006. Rene Rivera + * Copyright 2006-2022 René Ferdinand Rivera Morell * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE.txt or copy at * https://www.bfgroup.xyz/b2/LICENSE.txt) @@ -10,63 +10,63 @@ #include "config.h" -/* Standard C memory allocation. */ -#include +#include +#include -#define bjam_malloc_x(s) malloc(s) -#define bjam_calloc_x(n,s) calloc(n,s) -#define bjam_realloc_x(p,s) realloc(p,s) -#define bjam_free_x(p) free(p) +#define bjam_malloc_x(s) std::malloc(s) +#define bjam_calloc_x(n, s) std::calloc(n, s) +#define bjam_realloc_x(p, s) std::realloc(p, s) +#define bjam_free_x(p) std::free(p) #ifndef bjam_malloc_atomic_x - #define bjam_malloc_atomic_x(s) bjam_malloc_x(s) +#define bjam_malloc_atomic_x(s) bjam_malloc_x(s) #endif #ifndef bjam_calloc_atomic_x - #define bjam_calloc_atomic_x(n,s) bjam_calloc_x(n,s) +#define bjam_calloc_atomic_x(n, s) bjam_calloc_x(n, s) #endif #ifndef bjam_mem_init_x - #define bjam_mem_init_x() +#define bjam_mem_init_x() #endif #ifndef bjam_mem_close_x - #define bjam_mem_close_x() +#define bjam_mem_close_x() #endif #ifndef bjam_malloc_raw_x - #define bjam_malloc_raw_x(s) bjam_malloc_x(s) +#define bjam_malloc_raw_x(s) bjam_malloc_x(s) #endif #ifndef bjam_calloc_raw_x - #define bjam_calloc_raw_x(n,s) bjam_calloc_x(n,s) +#define bjam_calloc_raw_x(n, s) bjam_calloc_x(n, s) #endif #ifndef bjam_realloc_raw_x - #define bjam_realloc_raw_x(p,s) bjam_realloc_x(p,s) +#define bjam_realloc_raw_x(p, s) bjam_realloc_x(p, s) #endif #ifndef bjam_free_raw_x - #define bjam_free_raw_x(p) bjam_free_x(p) +#define bjam_free_raw_x(p) bjam_free_x(p) #endif #ifdef OPT_DEBUG_PROFILE - /* Profile tracing of memory allocations. */ - #include "debug.h" +/* Profile tracing of memory allocations. */ +#include "debug.h" - #define BJAM_MALLOC(s) (profile_memory(s), bjam_malloc_x(s)) - #define BJAM_MALLOC_ATOMIC(s) (profile_memory(s), bjam_malloc_atomic_x(s)) - #define BJAM_CALLOC(n,s) (profile_memory(n*s), bjam_calloc_x(n,s)) - #define BJAM_CALLOC_ATOMIC(n,s) (profile_memory(n*s), bjam_calloc_atomic_x(n,s)) - #define BJAM_REALLOC(p,s) (profile_memory(s), bjam_realloc_x(p,s)) +#define BJAM_MALLOC(s) (profile_memory(s), bjam_malloc_x(s)) +#define BJAM_MALLOC_ATOMIC(s) (profile_memory(s), bjam_malloc_atomic_x(s)) +#define BJAM_CALLOC(n, s) (profile_memory(n * s), bjam_calloc_x(n, s)) +#define BJAM_CALLOC_ATOMIC(n, s) (profile_memory(n * s), bjam_calloc_atomic_x(n, s)) +#define BJAM_REALLOC(p, s) (profile_memory(s), bjam_realloc_x(p, s)) - #define BJAM_MALLOC_RAW(s) (profile_memory(s), bjam_malloc_raw_x(s)) - #define BJAM_CALLOC_RAW(n,s) (profile_memory(n*s), bjam_calloc_raw_x(n,s)) - #define BJAM_REALLOC_RAW(p,s) (profile_memory(s), bjam_realloc_raw_x(p,s)) +#define BJAM_MALLOC_RAW(s) (profile_memory(s), bjam_malloc_raw_x(s)) +#define BJAM_CALLOC_RAW(n, s) (profile_memory(n * s), bjam_calloc_raw_x(n, s)) +#define BJAM_REALLOC_RAW(p, s) (profile_memory(s), bjam_realloc_raw_x(p, s)) #else - /* No mem tracing. */ - #define BJAM_MALLOC(s) bjam_malloc_x(s) - #define BJAM_MALLOC_ATOMIC(s) bjam_malloc_atomic_x(s) - #define BJAM_CALLOC(n,s) bjam_calloc_x(n,s) - #define BJAM_CALLOC_ATOMIC(n,s) bjam_calloc_atomic_x(n,s) - #define BJAM_REALLOC(p,s) bjam_realloc_x(p,s) +/* No mem tracing. */ +#define BJAM_MALLOC(s) bjam_malloc_x(s) +#define BJAM_MALLOC_ATOMIC(s) bjam_malloc_atomic_x(s) +#define BJAM_CALLOC(n, s) bjam_calloc_x(n, s) +#define BJAM_CALLOC_ATOMIC(n, s) bjam_calloc_atomic_x(n, s) +#define BJAM_REALLOC(p, s) bjam_realloc_x(p, s) - #define BJAM_MALLOC_RAW(s) bjam_malloc_raw_x(s) - #define BJAM_CALLOC_RAW(n,s) bjam_calloc_raw_x(n,s) - #define BJAM_REALLOC_RAW(p,s) bjam_realloc_raw_x(p,s) +#define BJAM_MALLOC_RAW(s) bjam_malloc_raw_x(s) +#define BJAM_CALLOC_RAW(n, s) bjam_calloc_raw_x(n, s) +#define BJAM_REALLOC_RAW(p, s) bjam_realloc_raw_x(p, s) #endif #define BJAM_MEM_INIT() bjam_mem_init_x() @@ -75,4 +75,48 @@ #define BJAM_FREE(p) bjam_free_x(p) #define BJAM_FREE_RAW(p) bjam_free_raw_x(p) +namespace b2 { +namespace jam { + + template + T* ctor_ptr(void* p, Args&&... args) + { + std::memset(p, 0, sizeof(T)); + return new (p) T(std::forward(args)...); + } + + template + T* make_ptr(Args&&... args) + { + return ctor_ptr(BJAM_MALLOC(sizeof(T))); + } + + template + void free_ptr(T* p) + { + p->~T(); + BJAM_FREE(p); + } + + template + struct unique_jptr_deleter { + void operator()(T* p) const + { + p->~T(); + BJAM_FREE(p); + } + }; + + template + using unique_jptr = std::unique_ptr>; + + template + unique_jptr make_unique_jptr(Args&&... args) + { + return unique_jptr(make_ptr(std::forward(args)...)); + } + +} +} + #endif diff --git a/src/engine/rules.cpp b/src/engine/rules.cpp index 7b77b920d..51f108d16 100644 --- a/src/engine/rules.cpp +++ b/src/engine/rules.cpp @@ -34,6 +34,7 @@ #include "hash.h" #include "lists.h" #include "object.h" +#include "output.h" #include "parse.h" #include "pathsys.h" #include "search.h" @@ -59,8 +60,7 @@ static target_ptr get_target_includes( target_ptr const t ) { if ( !t->includes ) { - target_ptr const i = (target_ptr)BJAM_MALLOC( sizeof( *t ) ); - memset( (char *)i, '\0', sizeof( *i ) ); + target_ptr const i = b2::jam::make_ptr<_target>(); i->name = object_copy( t->name ); i->boundname = object_copy( i->name ); i->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL; @@ -81,14 +81,14 @@ static target_ptr get_target_includes( target_ptr const t ) void target_include( target_ptr const including, target_ptr const included ) { target_ptr const internal = get_target_includes( including ); - internal->depends = targetentry( internal->depends, included ); + targetentry( internal->depends, included ); } void target_include_many( target_ptr const including, list_ptr const included_names ) { target_ptr const internal = get_target_includes( including ); - internal->depends = targetlist( internal->depends, included_names ); + targetlist( internal->depends, included_names ); } @@ -165,7 +165,7 @@ target_ptr bindtarget( object_ptr const target_name ) t = (target_ptr)hash_insert( targethash, target_name, &found ); if ( !found ) { - memset( (char *)t, '\0', sizeof( *t ) ); + b2::jam::ctor_ptr<_target>(t); t->name = object_copy( target_name ); t->boundname = object_copy( t->name ); /* default for T_FLAG_NOTFILE */ } @@ -237,13 +237,12 @@ target_ptr target_scc( target_ptr t ) * targets list of target names */ -targets_ptr targetlist( targets_ptr chain, list_ptr target_names ) +void targetlist( targets_uptr& chain, list_ptr target_names ) { LISTITER iter = list_begin( target_names ); LISTITER const end = list_end( target_names ); for ( ; iter != end; iter = list_next( iter ) ) - chain = targetentry( chain, bindtarget( list_item( iter ) ) ); - return chain; + targetentry( chain, bindtarget( list_item( iter ) ) ); } @@ -255,17 +254,15 @@ targets_ptr targetlist( targets_ptr chain, list_ptr target_names ) * target new target to append */ -targets_ptr targetentry( targets_ptr chain, target_ptr target ) +void targetentry( targets_uptr& chain, target_ptr target ) { - targets_ptr const c = (targets_ptr)BJAM_MALLOC( sizeof( TARGETS ) ); + auto c = b2::jam::make_unique_jptr(); c->target = target; - if ( !chain ) chain = c; - else chain->tail->next = c; - chain->tail = c; - c->next = 0; - - return chain; + targets_ptr tail = c.get(); + if ( !chain ) chain.reset(c.release()); + else chain->tail->next.reset(c.release()); + chain->tail = tail; } @@ -277,13 +274,26 @@ targets_ptr targetentry( targets_ptr chain, target_ptr target ) * target new target to append */ -targets_ptr targetchain( targets_ptr chain, targets_ptr targets ) +targets_uptr targetchain( targets_uptr chain, targets_uptr targets ) { if ( !targets ) return chain; if ( !chain ) return targets; - chain->tail->next = targets; - chain->tail = targets->tail; + targets_ptr tail = targets->tail; + chain->tail->next = std::move(targets); + chain->tail = tail; + return chain; +} + +/* + * targets_pop() - removes the first TARGET from the chain. + */ + +targets_uptr targets_pop(targets_uptr chain) +{ + if ( chain && chain->next ) + chain->next->tail = chain->tail; + chain = std::move( chain->next ); return chain; } @@ -295,9 +305,7 @@ void action_free( action_ptr action ) { if ( --action->refs == 0 ) { - freetargets( action->targets ); - freetargets( action->sources ); - BJAM_FREE( action ); + b2::jam::free_ptr(action); } } @@ -408,21 +416,6 @@ settings_ptr copysettings( settings_ptr head ) } -/* - * freetargets() - delete a targets list. - */ - -void freetargets( targets_ptr chain ) -{ - while ( chain ) - { - targets_ptr const n = chain->next; - BJAM_FREE( chain ); - chain = n; - } -} - - /* * freeactions() - delete an action list. */ @@ -462,15 +455,16 @@ static void freetarget( target_ptr const t, void * ) if ( t->name ) object_free ( t->name ); if ( t->boundname ) object_free ( t->boundname ); if ( t->settings ) freesettings( t->settings ); - if ( t->depends ) freetargets ( t->depends ); - if ( t->dependants ) freetargets ( t->dependants ); - if ( t->parents ) freetargets ( t->parents ); + if ( t->depends ) t->depends.reset(); + if ( t->dependants ) t->dependants.reset(); + if ( t->parents ) t->parents.reset(); if ( t->actions ) freeactions ( t->actions ); if ( t->includes ) { freetarget( t->includes, (void *)0 ); BJAM_FREE( t->includes ); } + t->~_target(); } diff --git a/src/engine/rules.h b/src/engine/rules.h index 43934b938..57b878133 100644 --- a/src/engine/rules.h +++ b/src/engine/rules.h @@ -32,6 +32,7 @@ #include "config.h" #include "function.h" +#include "mem.h" #include "modules.h" #include "timestamp.h" @@ -49,6 +50,20 @@ typedef ACTION* action_ptr; typedef ACTIONS* actions_ptr; typedef SETTINGS* settings_ptr; +typedef RULE& rule_ref; +typedef TARGET& target_ref; +typedef TARGETS& targets_ref; +typedef ACTION& action_ref; +typedef ACTIONS& actions_ref; +typedef SETTINGS& settings_ref; + +using rule_uptr = b2::jam::unique_jptr<_rule>; +using target_uptr = b2::jam::unique_jptr<_target>; +using targets_uptr = b2::jam::unique_jptr<_targets>; +using action_uptr = b2::jam::unique_jptr<_action>; +using actions_uptr = b2::jam::unique_jptr<_actions>; +using settings_uptr = b2::jam::unique_jptr<_settings>; + /* RULE - a generic jam rule, the product of RULE and ACTIONS. */ /* Build actions corresponding to a rule. */ @@ -89,8 +104,8 @@ struct _actions { /* ACTION - a RULE instance with targets and sources. */ struct _action { rule_ptr rule; - targets_ptr targets; - targets_ptr sources; /* aka $(>) */ + targets_uptr targets; + targets_uptr sources; /* aka $(>) */ char running; /* has been started */ #define A_INIT 0 #define A_RUNNING_NOEXEC 1 @@ -113,9 +128,9 @@ struct _settings { /* TARGETS - a chain of TARGETs. */ struct _targets { - targets_ptr next; - targets_ptr tail; /* valid only for head */ - target_ptr target; + targets_uptr next = nullptr; + targets_ptr tail = nullptr; /* valid only for head */ + target_ptr target = nullptr; }; /* TARGET - an entity (e.g. a file) that can be built. */ @@ -125,11 +140,11 @@ struct _target { actions_ptr actions; /* rules to execute, if any */ settings_ptr settings; /* variables to define */ - targets_ptr depends; /* dependencies */ - targets_ptr dependants; /* the inverse of dependencies */ - targets_ptr rebuilds; /* targets that should be force-rebuilt - * whenever this one is - */ + targets_uptr depends; /* dependencies */ + targets_uptr dependants; /* the inverse of dependencies */ + targets_uptr rebuilds; /* targets that should be force-rebuilt + * whenever this one is + */ target_ptr includes; /* internal includes node */ timestamp time; /* update time */ @@ -217,7 +232,7 @@ struct _target { #endif int asynccnt; /* child deps outstanding */ - targets_ptr parents; /* used by make1() for completion */ + targets_uptr parents; /* used by make1() for completion */ target_ptr scc_root; /* used by make to resolve cyclic includes */ target_ptr rescanning; /* used by make0 to mark visited targets @@ -254,17 +269,17 @@ void rule_free(rule_ptr); /* Target related functions. */ void bind_explicitly_located_targets(); target_ptr bindtarget(object_ptr const); -void freetargets(targets_ptr); -targets_ptr targetchain(targets_ptr, targets_ptr); -targets_ptr targetentry(targets_ptr, target_ptr); +targets_uptr targetchain(targets_uptr, targets_uptr); +void targetentry(targets_uptr&, target_ptr); void target_include(target_ptr const including, target_ptr const included); void target_include_many(target_ptr const including, list_ptr const included_names); -targets_ptr targetlist(targets_ptr, list_ptr target_names); +void targetlist(targets_uptr&, list_ptr target_names); void touch_target(object_ptr const); void clear_includes(target_ptr); target_ptr target_scc(target_ptr); +targets_uptr targets_pop(targets_uptr); /* Final module cleanup. */ void rules_done();