last updated:
Don't
The compiler is designed to take advantage of the fact that compilation has known phase ordering so that entire chunks of memory can be totally freed upon completion of a specific phase. A memory pool push/pop mechanism is designed to manage memory usage on top of STL's segmented array.
1. The old C style way
MEM_POOL_Push(&MEM_local_pool); MEM_POOL_Push(&MEM_local_nz_pool);
the two different pools are passed to relevant routines that needs memory, later on, used like the following:
loop_set = BB_SET_Create_Empty(PU_BB_Count + 2, pool);
where pool is the parameter with actual being &MEM_local_pool
There needs to be a finalize routine that pops the mempools.
2. a little newer way, for local temp memory, this method can simply use alloca e.g.
Local_Insn_Sched (void) { for (bb = REGION_First_BB; bb != NULL; bb = BB_next(bb)) { if (bb->Spilled() || !bb->Scheduled()) { MEM_POOL_Push(&MEM_local_pool); sched = CXX_NEW(LOCAL_SCHEDULER(bb), &MEM_local_pool); sched->Schedule(); CXX_DELETE(LOCAL_SCHEDULER(bb), &MEM_local_pool); MEM_POOL_Pop(&MEM_local_pool); } } }3. a more sophistical way that works in cg phase also, taking
the fb_cfg.h and fg_cfg.cxx as example class FB_CFG_MEM { protected: MEM_POOL _m; FB_CFG_MEM() { MEM_POOL_Initialize( &_m, "FB_CFG_MEM", true); MEM_POOL_Push( &_m ); } ~FB_CFG_MEM() { MEM_POOL_Pop( &_m ); MEM_POOL_Delete( &_m ); } }; FB_CFG: public FB_CFG_MEM { ... hashmap< LABEL_IDX, FB_NODEX, hash<LABEL_IDX>, equal_to<LABEL_IDX>, mempool_allocator< pair<LABEL_IDX, FBNODEX> > > _lblx_to_nx; deque< FB_EDGE_DELAYED, mempool_allocator<FB_EDGE_DELAYED> > _delayed_edges; FB_NODEX _curr_nx; ... };The FB_CFG graph is implemented as a deque of nodes and edges. Here, no mempool operation is exposed in the routines such as FB_CFG::New_Node, Add_edge. The constructors for the containers _nodes, _lblx_to_nx and _delayed_edges are explicitly called from the constructor of FB_CFG and the mempool _m is passed down there, making sure mempool is properly initialized, stacked and deleted upon exit.
#1 is NOT desirable since there hides an assumed method of push and pop with a initialize routine and finalize routine, but no way to enforce implementers to do that in the right sequence. Currently, CG uses #1 or #2. The problem with #2 is when you "break" out of loop or "return" from a procedure, you have to insert MEM_POOL_pop at each exit paths. And people usually don't get it correct the first time, or forget to add the necessary insert when fix bugs.
For #3, If you look at CXX_MEM_POOL, it does the same thing as FB_CFG_MEM. So class FB_CFG could have been declared as class FB_CFG : public CXX_MEM_POOL {...}; Memory used by the containers (i.e., the deque and hashmap here) is released by the containers themselves. In this example, itsimply tells the containers to use the specified mempool as memory allocator. Any object created by these containers will accquire memory from this mempool. And the memory will be released back to the mempool when these objects' destructors are called.