diff mbox

[RFC] Split pool_allocator and create a new object_allocator

Message ID 55914DB1.9000700@suse.cz
State New
Headers show

Commit Message

Martin Liška June 29, 2015, 1:52 p.m. UTC
Hello.

This mail thread is follow-up from the previous thread, where Ulrich Weigand spotted
a miscompilation:

https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00868.html

Following patch changes behavior of the pool_allocator:

1) pool_allocator is typeless and does not call any ctor
2) pool_allocator returns void* as a result of allocate function
3) all classes (e.g. et_occ) which use an operator new utilize
the typeless allocator

4) object_allocator is a new type-based allocator which is used for allocation of
objects
5) for a type T, the allocator calls placement new constructor and T* is return
type of the allocate function
6) the object_allocator internally utilizes pool_allocator with m_size == sizeof(T)

The patch can bootstrap on x86_64-unknown-linux-gnu and ppc64le-unknown-linux-gnu and
regression tests have been running.

Thoughts?
Thanks,
Martin

Comments

Richard Sandiford July 2, 2015, 8:09 p.m. UTC | #1
Martin Liška <mliska@suse.cz> writes:
> @@ -136,18 +135,18 @@ private:
>  	int64_t align_i;
>        } u;
>  
> -    static inline allocation_object<U> *
> +    static inline allocation_object*

space before "*"

>      get_instance (void *data_ptr)
>      {
> -      return (allocation_object<U> *)(((char *)(data_ptr))
> -				      - offsetof (allocation_object<U>,
> +      return (allocation_object *)(((char *)(data_ptr))
> +				      - offsetof (allocation_object,
>  						  u.data));

space between ")" and "(".

>      }
>  
> -    static inline U *
> +    static inline void*
>      get_data (void *instance_ptr)
>      {
> -      return (U*)(((allocation_object<U> *) instance_ptr)->u.data);
> +      return (void*)(((allocation_object *) instance_ptr)->u.data);

same 2 comments here, although maybe dropping the cast would be better?

> @@ -387,11 +349,11 @@ pool_allocator<T>::allocate ()
>        /* We now know that we can take the first elt off the virgin list and
>  	 put it on the returned list.  */
>        block = m_virgin_free_list;
> -      header = (allocation_pool_list*) allocation_object<T>::get_data (block);
> +      header = (allocation_pool_list*) allocation_object::get_data (block);

Space before "*".  I'll not list out the others :-)

> @@ -408,36 +370,34 @@ pool_allocator<T>::allocate ()
>  
>  #ifdef ENABLE_CHECKING
>    /* Set the ID for element.  */
> -  allocation_object<T>::get_instance (header)->id = m_id;
> +  allocation_object::get_instance (header)->id = m_id;
>  #endif
>    VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (header, size));
>  
> -  /* Call default constructor.  */
> -  return (T *)(header);
> +  return (void *)(header);

Same comment about cast to void *.

> diff --git a/gcc/asan.c b/gcc/asan.c
> index e89817e..dabd6f1 100644
> --- a/gcc/asan.c
> +++ b/gcc/asan.c
> @@ -362,20 +362,20 @@ struct asan_mem_ref
>    /* Pool allocation new operator.  */
>    inline void *operator new (size_t)
>    {
> -    return pool.allocate ();
> +    return ::new (pool.allocate ()) asan_mem_ref ();
>    }
>  
>    /* Delete operator utilizing pool allocation.  */
>    inline void operator delete (void *ptr)
>    {
> -    pool.remove ((asan_mem_ref *) ptr);
> +    pool.remove (ptr);
>    }
>  
>    /* Memory allocation pool.  */
> -  static pool_allocator<asan_mem_ref> pool;
> +  static pool_allocator pool;
>  };

I'm probably going over old ground/wounds, sorry, but what's the benefit
of having this sort of pattern?  Why not simply have object_allocators
and make callers use pool.allocate () and pool.remove (x) (with pool.remove
calling the destructor) instead of new and delete?  It feels wrong to me
to tie the data type to a particular allocation object like this.
And using the pool allocator functions directly has the nice property
that you can tell when a delete/remove isn't necessary because the pool
itself is being cleared.

Thanks,
Richard
Trevor Saunders July 2, 2015, 9:08 p.m. UTC | #2
On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
> Martin Liška <mliska@suse.cz> writes:
> > diff --git a/gcc/asan.c b/gcc/asan.c
> > index e89817e..dabd6f1 100644
> > --- a/gcc/asan.c
> > +++ b/gcc/asan.c
> > @@ -362,20 +362,20 @@ struct asan_mem_ref
> >    /* Pool allocation new operator.  */
> >    inline void *operator new (size_t)
> >    {
> > -    return pool.allocate ();
> > +    return ::new (pool.allocate ()) asan_mem_ref ();
> >    }
> >  
> >    /* Delete operator utilizing pool allocation.  */
> >    inline void operator delete (void *ptr)
> >    {
> > -    pool.remove ((asan_mem_ref *) ptr);
> > +    pool.remove (ptr);
> >    }
> >  
> >    /* Memory allocation pool.  */
> > -  static pool_allocator<asan_mem_ref> pool;
> > +  static pool_allocator pool;
> >  };
> 
> I'm probably going over old ground/wounds, sorry, but what's the benefit
> of having this sort of pattern?  Why not simply have object_allocators
> and make callers use pool.allocate () and pool.remove (x) (with pool.remove
> calling the destructor) instead of new and delete?  It feels wrong to me
> to tie the data type to a particular allocation object like this.

Well the big question is what does allocate() do about construction?  if
it seems wierd for it to not call the ctor, but I'm not sure we can do a
good job of forwarding args to allocate() with C++98.

However it seems kind of wierd the operator new here is calling the
placement new on the object it allocates.

> And using the pool allocator functions directly has the nice property
> that you can tell when a delete/remove isn't necessary because the pool
> itself is being cleared.

Well, all these cases involve a pool with static storage lifetime right?
so actually if you don't delete things in these pool they are
effectively leaked.

Trev

> 
> Thanks,
> Richard
Richard Sandiford July 3, 2015, 8:55 a.m. UTC | #3
Trevor Saunders <tbsaunde@tbsaunde.org> writes:
> On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
>> Martin Liška <mliska@suse.cz> writes:
>> > diff --git a/gcc/asan.c b/gcc/asan.c
>> > index e89817e..dabd6f1 100644
>> > --- a/gcc/asan.c
>> > +++ b/gcc/asan.c
>> > @@ -362,20 +362,20 @@ struct asan_mem_ref
>> >    /* Pool allocation new operator.  */
>> >    inline void *operator new (size_t)
>> >    {
>> > -    return pool.allocate ();
>> > +    return ::new (pool.allocate ()) asan_mem_ref ();
>> >    }
>> >  
>> >    /* Delete operator utilizing pool allocation.  */
>> >    inline void operator delete (void *ptr)
>> >    {
>> > -    pool.remove ((asan_mem_ref *) ptr);
>> > +    pool.remove (ptr);
>> >    }
>> >  
>> >    /* Memory allocation pool.  */
>> > -  static pool_allocator<asan_mem_ref> pool;
>> > +  static pool_allocator pool;
>> >  };
>> 
>> I'm probably going over old ground/wounds, sorry, but what's the benefit
>> of having this sort of pattern?  Why not simply have object_allocators
>> and make callers use pool.allocate () and pool.remove (x) (with pool.remove
>> calling the destructor) instead of new and delete?  It feels wrong to me
>> to tie the data type to a particular allocation object like this.
>
> Well the big question is what does allocate() do about construction?  if
> it seems wierd for it to not call the ctor, but I'm not sure we can do a
> good job of forwarding args to allocate() with C++98.

If you need non-default constructors then:

  new (pool) type (aaa, bbb)...;

doesn't seem too bad.  I agree object_allocator's allocate () should call
the constructor.

> However it seems kind of wierd the operator new here is calling the
> placement new on the object it allocates.

Yeah.

>> And using the pool allocator functions directly has the nice property
>> that you can tell when a delete/remove isn't necessary because the pool
>> itself is being cleared.
>
> Well, all these cases involve a pool with static storage lifetime right?
> so actually if you don't delete things in these pool they are
> effectively leaked.

They might have a static storage lifetime now, but it doesn't seem like
a good idea to hard-bake that into the interface (by saying that for
these types you should use new and delete, but for other pool-allocated
types you should use object_allocators).  Maybe I just have bad memories
from doing the SWITCHABLE_TARGET stuff, but there I was changing a lot
of state that was "obviously" static in the old days, but that needed
to become non-static to support vaguely-efficient switching between
different subtargets.  The same kind of thing is likely to happen again.
I assume things like the jit would prefer not to have new global state
with load-time construction.

Thanks,
Richard
Martin Liška July 3, 2015, 10:11 a.m. UTC | #4
On 07/03/2015 10:55 AM, Richard Sandiford wrote:
> Trevor Saunders <tbsaunde@tbsaunde.org> writes:
>> On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
>>> Martin Liška <mliska@suse.cz> writes:
>>>> diff --git a/gcc/asan.c b/gcc/asan.c
>>>> index e89817e..dabd6f1 100644
>>>> --- a/gcc/asan.c
>>>> +++ b/gcc/asan.c
>>>> @@ -362,20 +362,20 @@ struct asan_mem_ref
>>>>    /* Pool allocation new operator.  */
>>>>    inline void *operator new (size_t)
>>>>    {
>>>> -    return pool.allocate ();
>>>> +    return ::new (pool.allocate ()) asan_mem_ref ();
>>>>    }
>>>>  
>>>>    /* Delete operator utilizing pool allocation.  */
>>>>    inline void operator delete (void *ptr)
>>>>    {
>>>> -    pool.remove ((asan_mem_ref *) ptr);
>>>> +    pool.remove (ptr);
>>>>    }
>>>>  
>>>>    /* Memory allocation pool.  */
>>>> -  static pool_allocator<asan_mem_ref> pool;
>>>> +  static pool_allocator pool;
>>>>  };
>>>
>>> I'm probably going over old ground/wounds, sorry, but what's the benefit
>>> of having this sort of pattern?  Why not simply have object_allocators
>>> and make callers use pool.allocate () and pool.remove (x) (with pool.remove
>>> calling the destructor) instead of new and delete?  It feels wrong to me
>>> to tie the data type to a particular allocation object like this.
>>
>> Well the big question is what does allocate() do about construction?  if
>> it seems wierd for it to not call the ctor, but I'm not sure we can do a
>> good job of forwarding args to allocate() with C++98.
> 
> If you need non-default constructors then:
> 
>   new (pool) type (aaa, bbb)...;
> 
> doesn't seem too bad.  I agree object_allocator's allocate () should call
> the constructor.

Hello.

I do not insist on having a new/delete operator for aforementioned class.
However, I don't know a different approach that will do an object construction
in the allocate method w/o utilizing placement new?

> 
>> However it seems kind of wierd the operator new here is calling the
>> placement new on the object it allocates.
> 
> Yeah.
> 
>>> And using the pool allocator functions directly has the nice property
>>> that you can tell when a delete/remove isn't necessary because the pool
>>> itself is being cleared.
>>
>> Well, all these cases involve a pool with static storage lifetime right?
>> so actually if you don't delete things in these pool they are
>> effectively leaked.
> 
> They might have a static storage lifetime now, but it doesn't seem like
> a good idea to hard-bake that into the interface (by saying that for
> these types you should use new and delete, but for other pool-allocated
> types you should use object_allocators).  Maybe I just have bad memories
> from doing the SWITCHABLE_TARGET stuff, but there I was changing a lot
> of state that was "obviously" static in the old days, but that needed
> to become non-static to support vaguely-efficient switching between
> different subtargets.  The same kind of thing is likely to happen again.
> I assume things like the jit would prefer not to have new global state
> with load-time construction.

Agree with that it's a global state. But even before my transformation the code
utilized static variables that are similar problem from e.g. JIT perspective. Best
approach would be to encapsulate these static allocators to a class (a pass?). It's
quite a lot of work.

Thanks,
Martin

> 
> Thanks,
> Richard
>
Martin Jambor July 3, 2015, 12:22 p.m. UTC | #5
Hi,

On Fri, Jul 03, 2015 at 09:55:58AM +0100, Richard Sandiford wrote:
> Trevor Saunders <tbsaunde@tbsaunde.org> writes:
> > On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
> >> Martin Liška <mliska@suse.cz> writes:
> >> > diff --git a/gcc/asan.c b/gcc/asan.c
> >> > index e89817e..dabd6f1 100644
> >> > --- a/gcc/asan.c
> >> > +++ b/gcc/asan.c
> >> > @@ -362,20 +362,20 @@ struct asan_mem_ref
> >> >    /* Pool allocation new operator.  */
> >> >    inline void *operator new (size_t)
> >> >    {
> >> > -    return pool.allocate ();
> >> > +    return ::new (pool.allocate ()) asan_mem_ref ();
> >> >    }
> >> >  
> >> >    /* Delete operator utilizing pool allocation.  */
> >> >    inline void operator delete (void *ptr)
> >> >    {
> >> > -    pool.remove ((asan_mem_ref *) ptr);
> >> > +    pool.remove (ptr);
> >> >    }
> >> >  
> >> >    /* Memory allocation pool.  */
> >> > -  static pool_allocator<asan_mem_ref> pool;
> >> > +  static pool_allocator pool;
> >> >  };
> >> 
> >> I'm probably going over old ground/wounds, sorry, but what's the benefit
> >> of having this sort of pattern?  Why not simply have object_allocators
> >> and make callers use pool.allocate () and pool.remove (x) (with pool.remove
> >> calling the destructor) instead of new and delete?  It feels wrong to me
> >> to tie the data type to a particular allocation object like this.
> >
> > Well the big question is what does allocate() do about construction?  if
> > it seems wierd for it to not call the ctor, but I'm not sure we can do a
> > good job of forwarding args to allocate() with C++98.
> 
> If you need non-default constructors then:
> 
>   new (pool) type (aaa, bbb)...;
> 
> doesn't seem too bad.  I agree object_allocator's allocate () should call
> the constructor.
> 

but then the pool allocator must not call placement new on the
allocated memory itself because that would result in double
construction.  And calling placement new was explicitely requested in
the previous thread about allocators, so we still need two kinds of
allocators, typed and untyped.  Or just the untyped allocators and
requiring that users construct their objects via placement new.  In
fact, they might have to call placement new even if there is no
constructor because of the weird aliasing issue.  Two kinds of
pool-allocators seem the lesser evil to me.

> >> And using the pool allocator functions directly has the nice property
> >> that you can tell when a delete/remove isn't necessary because the pool
> >> itself is being cleared.
> >
> > Well, all these cases involve a pool with static storage lifetime right?
> > so actually if you don't delete things in these pool they are
> > effectively leaked.
> 
> They might have a static storage lifetime now, but it doesn't seem like
> a good idea to hard-bake that into the interface

Does that mean that operators new and delete are considered evil?

> (by saying that for
> these types you should use new and delete, but for other pool-allocated
> types you should use object_allocators).

Depending on what kind of pool allocator you use, you will be forced
to either call placement new or not, so the inconsistency will be
there anyway.

I'm using pool allocators for classes with non-default constructors a
lot in the HSA branch so I'd appreciate an early settlement of this
issue.  I think I slightly prefer overloading new and delete to using
placement new (at least in new code) because then users just allocate
stuff as usual and there is one central point where thing can be
changed.  But I do not have strong feelings and will comply with
whatever we can agree on.

> Maybe I just have bad memories
> from doing the SWITCHABLE_TARGET stuff, but there I was changing a lot
> of state that was "obviously" static in the old days, but that needed
> to become non-static to support vaguely-efficient switching between
> different subtargets.  The same kind of thing is likely to happen again.
> I assume things like the jit would prefer not to have new global state
> with load-time construction.

I'm not sure I follow this branch of the discussion, the allocators of
any kind surely can dynamically allocated themselves?

Thanks,

Martin
Richard Sandiford July 3, 2015, 1:07 p.m. UTC | #6
Martin Jambor <mjambor@suse.cz> writes:
> On Fri, Jul 03, 2015 at 09:55:58AM +0100, Richard Sandiford wrote:
>> Trevor Saunders <tbsaunde@tbsaunde.org> writes:
>> > On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
>> >> Martin Liška <mliska@suse.cz> writes:
>> >> > diff --git a/gcc/asan.c b/gcc/asan.c
>> >> > index e89817e..dabd6f1 100644
>> >> > --- a/gcc/asan.c
>> >> > +++ b/gcc/asan.c
>> >> > @@ -362,20 +362,20 @@ struct asan_mem_ref
>> >> >    /* Pool allocation new operator.  */
>> >> >    inline void *operator new (size_t)
>> >> >    {
>> >> > -    return pool.allocate ();
>> >> > +    return ::new (pool.allocate ()) asan_mem_ref ();
>> >> >    }
>> >> >  
>> >> >    /* Delete operator utilizing pool allocation.  */
>> >> >    inline void operator delete (void *ptr)
>> >> >    {
>> >> > -    pool.remove ((asan_mem_ref *) ptr);
>> >> > +    pool.remove (ptr);
>> >> >    }
>> >> >  
>> >> >    /* Memory allocation pool.  */
>> >> > -  static pool_allocator<asan_mem_ref> pool;
>> >> > +  static pool_allocator pool;
>> >> >  };
>> >> 
>> >> I'm probably going over old ground/wounds, sorry, but what's the benefit
>> >> of having this sort of pattern?  Why not simply have object_allocators
>> >> and make callers use pool.allocate () and pool.remove (x) (with pool.remove
>> >> calling the destructor) instead of new and delete?  It feels wrong to me
>> >> to tie the data type to a particular allocation object like this.
>> >
>> > Well the big question is what does allocate() do about construction?  if
>> > it seems wierd for it to not call the ctor, but I'm not sure we can do a
>> > good job of forwarding args to allocate() with C++98.
>> 
>> If you need non-default constructors then:
>> 
>>   new (pool) type (aaa, bbb)...;
>> 
>> doesn't seem too bad.  I agree object_allocator's allocate () should call
>> the constructor.
>> 
>
> but then the pool allocator must not call placement new on the
> allocated memory itself because that would result in double
> construction.

But we're talking about two different methods.  The "normal" allocator
object_allocator <T>::allocate () would use placement new and return a
pointer to the new object while operator new (size_t, object_allocator <T> &)
wouldn't call placement new and would just return a pointer to the memory.

>> >> And using the pool allocator functions directly has the nice property
>> >> that you can tell when a delete/remove isn't necessary because the pool
>> >> itself is being cleared.
>> >
>> > Well, all these cases involve a pool with static storage lifetime right?
>> > so actually if you don't delete things in these pool they are
>> > effectively leaked.
>> 
>> They might have a static storage lifetime now, but it doesn't seem like
>> a good idea to hard-bake that into the interface
>
> Does that mean that operators new and delete are considered evil?

Not IMO.  Just that static load-time-initialized caches are not
necessarily a good thing.  That's effectively what the pool
allocator is.

>> (by saying that for
>> these types you should use new and delete, but for other pool-allocated
>> types you should use object_allocators).
>
> Depending on what kind of pool allocator you use, you will be forced
> to either call placement new or not, so the inconsistency will be
> there anyway.

But how we handle argument-taking constructors is a problem that needs
to be solved for the pool-allocated objects that don't use a single
static type-specific pool.  And once we solve that, we get consistency
across all pools:

- if you want a new object and argumentless construction is OK,
  use "pool.allocate ()"

- if you want a new object and need to pass arguments to the constructor,
  use "new (pool) some_type (arg1, arg2, ...)"

>> Maybe I just have bad memories
>> from doing the SWITCHABLE_TARGET stuff, but there I was changing a lot
>> of state that was "obviously" static in the old days, but that needed
>> to become non-static to support vaguely-efficient switching between
>> different subtargets.  The same kind of thing is likely to happen again.
>> I assume things like the jit would prefer not to have new global state
>> with load-time construction.
>
> I'm not sure I follow this branch of the discussion, the allocators of
> any kind surely can dynamically allocated themselves?

Sure, but either (a) you keep the pools as a static part of the class
and some initialisation and finalisation code that has tendrils into
all such classes or (b) you move the static pool outside of the
class to some new (still global) state.  Explicit pool allocation,
like in the C days, gives you the option of putting the pool whereever
it needs to go without relying on the principle that you can get to
it from global state.

Thanks,
Richard
Martin Liška July 3, 2015, 2:15 p.m. UTC | #7
On 07/03/2015 03:07 PM, Richard Sandiford wrote:
> Martin Jambor <mjambor@suse.cz> writes:
>> On Fri, Jul 03, 2015 at 09:55:58AM +0100, Richard Sandiford wrote:
>>> Trevor Saunders <tbsaunde@tbsaunde.org> writes:
>>>> On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
>>>>> Martin Liška <mliska@suse.cz> writes:
>>>>>> diff --git a/gcc/asan.c b/gcc/asan.c
>>>>>> index e89817e..dabd6f1 100644
>>>>>> --- a/gcc/asan.c
>>>>>> +++ b/gcc/asan.c
>>>>>> @@ -362,20 +362,20 @@ struct asan_mem_ref
>>>>>>    /* Pool allocation new operator.  */
>>>>>>    inline void *operator new (size_t)
>>>>>>    {
>>>>>> -    return pool.allocate ();
>>>>>> +    return ::new (pool.allocate ()) asan_mem_ref ();
>>>>>>    }
>>>>>>  
>>>>>>    /* Delete operator utilizing pool allocation.  */
>>>>>>    inline void operator delete (void *ptr)
>>>>>>    {
>>>>>> -    pool.remove ((asan_mem_ref *) ptr);
>>>>>> +    pool.remove (ptr);
>>>>>>    }
>>>>>>  
>>>>>>    /* Memory allocation pool.  */
>>>>>> -  static pool_allocator<asan_mem_ref> pool;
>>>>>> +  static pool_allocator pool;
>>>>>>  };
>>>>>
>>>>> I'm probably going over old ground/wounds, sorry, but what's the benefit
>>>>> of having this sort of pattern?  Why not simply have object_allocators
>>>>> and make callers use pool.allocate () and pool.remove (x) (with pool.remove
>>>>> calling the destructor) instead of new and delete?  It feels wrong to me
>>>>> to tie the data type to a particular allocation object like this.
>>>>
>>>> Well the big question is what does allocate() do about construction?  if
>>>> it seems wierd for it to not call the ctor, but I'm not sure we can do a
>>>> good job of forwarding args to allocate() with C++98.
>>>
>>> If you need non-default constructors then:
>>>
>>>   new (pool) type (aaa, bbb)...;
>>>
>>> doesn't seem too bad.  I agree object_allocator's allocate () should call
>>> the constructor.
>>>
>>
>> but then the pool allocator must not call placement new on the
>> allocated memory itself because that would result in double
>> construction.
> 
> But we're talking about two different methods.  The "normal" allocator
> object_allocator <T>::allocate () would use placement new and return a
> pointer to the new object while operator new (size_t, object_allocator <T> &)
> wouldn't call placement new and would just return a pointer to the memory.
> 
>>>>> And using the pool allocator functions directly has the nice property
>>>>> that you can tell when a delete/remove isn't necessary because the pool
>>>>> itself is being cleared.
>>>>
>>>> Well, all these cases involve a pool with static storage lifetime right?
>>>> so actually if you don't delete things in these pool they are
>>>> effectively leaked.
>>>
>>> They might have a static storage lifetime now, but it doesn't seem like
>>> a good idea to hard-bake that into the interface
>>
>> Does that mean that operators new and delete are considered evil?
> 
> Not IMO.  Just that static load-time-initialized caches are not
> necessarily a good thing.  That's effectively what the pool
> allocator is.
> 
>>> (by saying that for
>>> these types you should use new and delete, but for other pool-allocated
>>> types you should use object_allocators).
>>
>> Depending on what kind of pool allocator you use, you will be forced
>> to either call placement new or not, so the inconsistency will be
>> there anyway.
> 
> But how we handle argument-taking constructors is a problem that needs
> to be solved for the pool-allocated objects that don't use a single
> static type-specific pool.  And once we solve that, we get consistency
> across all pools:
> 
> - if you want a new object and argumentless construction is OK,
>   use "pool.allocate ()"
> 
> - if you want a new object and need to pass arguments to the constructor,
>   use "new (pool) some_type (arg1, arg2, ...)"
> 
>>> Maybe I just have bad memories
>>> from doing the SWITCHABLE_TARGET stuff, but there I was changing a lot
>>> of state that was "obviously" static in the old days, but that needed
>>> to become non-static to support vaguely-efficient switching between
>>> different subtargets.  The same kind of thing is likely to happen again.
>>> I assume things like the jit would prefer not to have new global state
>>> with load-time construction.
>>
>> I'm not sure I follow this branch of the discussion, the allocators of
>> any kind surely can dynamically allocated themselves?
> 
> Sure, but either (a) you keep the pools as a static part of the class
> and some initialisation and finalisation code that has tendrils into
> all such classes or (b) you move the static pool outside of the
> class to some new (still global) state.  Explicit pool allocation,
> like in the C days, gives you the option of putting the pool whereever
> it needs to go without relying on the principle that you can get to
> it from global state.
> 
> Thanks,
> Richard
> 

Ok Richard.

I've just finally understood your suggestions and I would suggest following:

+ I will add a new method to object_allocator<T> that will return an allocated memory (void*)
(w/o calling any construction)
+ object_allocator<T>::allocate will call placement new with for a parameterless ctor
+ I will remove all overwritten operators new/delete on e.g. et_forest, ...
+ For these classes, I will add void* operator new (size_t, object_allocator<T> &)
+ Pool allocators connected to these classes will be back transformed to static variables and
one would call new et_forest (my_et_forest_allocator)

Please confirm that aforementioned changes make sense and I'll come up with patch.
Thanks,
Martin
Richard Sandiford July 3, 2015, 4:18 p.m. UTC | #8
Hi Martin,

Martin Liška <mliska@suse.cz> writes:
> On 07/03/2015 03:07 PM, Richard Sandiford wrote:
>> Martin Jambor <mjambor@suse.cz> writes:
>>> On Fri, Jul 03, 2015 at 09:55:58AM +0100, Richard Sandiford wrote:
>>>> Trevor Saunders <tbsaunde@tbsaunde.org> writes:
>>>>> On Thu, Jul 02, 2015 at 09:09:31PM +0100, Richard Sandiford wrote:
>>>>>> Martin Liška <mliska@suse.cz> writes:
>>>>>>> diff --git a/gcc/asan.c b/gcc/asan.c
>>>>>>> index e89817e..dabd6f1 100644
>>>>>>> --- a/gcc/asan.c
>>>>>>> +++ b/gcc/asan.c
>>>>>>> @@ -362,20 +362,20 @@ struct asan_mem_ref
>>>>>>>    /* Pool allocation new operator.  */
>>>>>>>    inline void *operator new (size_t)
>>>>>>>    {
>>>>>>> -    return pool.allocate ();
>>>>>>> +    return ::new (pool.allocate ()) asan_mem_ref ();
>>>>>>>    }
>>>>>>>  
>>>>>>>    /* Delete operator utilizing pool allocation.  */
>>>>>>>    inline void operator delete (void *ptr)
>>>>>>>    {
>>>>>>> -    pool.remove ((asan_mem_ref *) ptr);
>>>>>>> +    pool.remove (ptr);
>>>>>>>    }
>>>>>>>  
>>>>>>>    /* Memory allocation pool.  */
>>>>>>> -  static pool_allocator<asan_mem_ref> pool;
>>>>>>> +  static pool_allocator pool;
>>>>>>>  };
>>>>>>
>>>>>> I'm probably going over old ground/wounds, sorry, but what's the benefit
>>>>>> of having this sort of pattern?  Why not simply have object_allocators
>>>>>> and make callers use pool.allocate () and pool.remove (x) (with
>>>>>> pool.remove
>>>>>> calling the destructor) instead of new and delete?  It feels wrong to me
>>>>>> to tie the data type to a particular allocation object like this.
>>>>>
>>>>> Well the big question is what does allocate() do about construction?  if
>>>>> it seems wierd for it to not call the ctor, but I'm not sure we can do a
>>>>> good job of forwarding args to allocate() with C++98.
>>>>
>>>> If you need non-default constructors then:
>>>>
>>>>   new (pool) type (aaa, bbb)...;
>>>>
>>>> doesn't seem too bad.  I agree object_allocator's allocate () should call
>>>> the constructor.
>>>>
>>>
>>> but then the pool allocator must not call placement new on the
>>> allocated memory itself because that would result in double
>>> construction.
>> 
>> But we're talking about two different methods.  The "normal" allocator
>> object_allocator <T>::allocate () would use placement new and return a
>> pointer to the new object while operator new (size_t, object_allocator <T> &)
>> wouldn't call placement new and would just return a pointer to the memory.
>> 
>>>>>> And using the pool allocator functions directly has the nice property
>>>>>> that you can tell when a delete/remove isn't necessary because the pool
>>>>>> itself is being cleared.
>>>>>
>>>>> Well, all these cases involve a pool with static storage lifetime right?
>>>>> so actually if you don't delete things in these pool they are
>>>>> effectively leaked.
>>>>
>>>> They might have a static storage lifetime now, but it doesn't seem like
>>>> a good idea to hard-bake that into the interface
>>>
>>> Does that mean that operators new and delete are considered evil?
>> 
>> Not IMO.  Just that static load-time-initialized caches are not
>> necessarily a good thing.  That's effectively what the pool
>> allocator is.
>> 
>>>> (by saying that for
>>>> these types you should use new and delete, but for other pool-allocated
>>>> types you should use object_allocators).
>>>
>>> Depending on what kind of pool allocator you use, you will be forced
>>> to either call placement new or not, so the inconsistency will be
>>> there anyway.
>> 
>> But how we handle argument-taking constructors is a problem that needs
>> to be solved for the pool-allocated objects that don't use a single
>> static type-specific pool.  And once we solve that, we get consistency
>> across all pools:
>> 
>> - if you want a new object and argumentless construction is OK,
>>   use "pool.allocate ()"
>> 
>> - if you want a new object and need to pass arguments to the constructor,
>>   use "new (pool) some_type (arg1, arg2, ...)"
>> 
>>>> Maybe I just have bad memories
>>>> from doing the SWITCHABLE_TARGET stuff, but there I was changing a lot
>>>> of state that was "obviously" static in the old days, but that needed
>>>> to become non-static to support vaguely-efficient switching between
>>>> different subtargets.  The same kind of thing is likely to happen again.
>>>> I assume things like the jit would prefer not to have new global state
>>>> with load-time construction.
>>>
>>> I'm not sure I follow this branch of the discussion, the allocators of
>>> any kind surely can dynamically allocated themselves?
>> 
>> Sure, but either (a) you keep the pools as a static part of the class
>> and some initialisation and finalisation code that has tendrils into
>> all such classes or (b) you move the static pool outside of the
>> class to some new (still global) state.  Explicit pool allocation,
>> like in the C days, gives you the option of putting the pool whereever
>> it needs to go without relying on the principle that you can get to
>> it from global state.
>> 
>> Thanks,
>> Richard
>> 
>
> Ok Richard.
>
> I've just finally understood your suggestions and I would suggest following:
>
> + I will add a new method to object_allocator<T> that will return an
> allocated memory (void*)
> (w/o calling any construction)
> + object_allocator<T>::allocate will call placement new with for a
> parameterless ctor
> + I will remove all overwritten operators new/delete on e.g. et_forest, ...
> + For these classes, I will add void* operator new (size_t,
> object_allocator<T> &)

I was thinking we'd simply use allocate () for cases where we don't
need to pass arguments to the constructor.  It looks like et_forest
comes into that category.  The operator new would be a single function
defined in pool-allocator.h for cases where explicit construction
is needed.

In fact, it looks from a quick grep like all current uses of pool operator
new/delete are in POD types, so there are no special constructors.
The best example I could come up with was the copy constructor in:

  return new lra_live_range (*r);

which would become:

  return new (*live_range_pool) lra_live_range (*r);

but perhaps we should have an object_allocator copy (T *) routine:

  return live_range_pool->copy (*r);

> + Pool allocators connected to these classes will be back transformed to
> static variables and
> one would call new et_forest (my_et_forest_allocator)

Thanks, this sounds really good to me.  Please make sure I'm not the
only one who thinks so though :-)

I think the "normal" remove () method should then also call the destructor.

Thanks,
Richard
diff mbox

Patch

From 9702a6ea0b60985f08ff28b0977c1dc46c25f27b Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Wed, 24 Jun 2015 13:42:52 +0200
Subject: [PATCH] Add new object_allocator.

gcc/c-family/ChangeLog:

2015-06-24  Martin Liska  <mliska@suse.cz>

	* c-format.c (static void check_format_info_main): Use
	object_allocator instead of pool_allocator.
	(check_format_arg): Likewise.
	(check_format_info_main): Likewise.

gcc/ChangeLog:

2015-06-24  Martin Liska  <mliska@suse.cz>

	* alloc-pool.h (pool_allocator::initialize): Change to type-less
	pool_allocator.
	(pool_allocator::allocate): Likewise.
	(pool_allocator::remove): Likewise.
	* asan.c (struct asan_mem_ref): Likewise.
	* cfg.c (initialize_original_copy_tables): Use object_allocator
	instead of pool_allocator.
	* cselib.c (struct elt_list): Change declaration of used
	pool_allocator.
	(new_cselib_val): Likewise.
	* cselib.h (struct cselib_val): Change to type-less pool_allocator..
	(struct elt_loc_list): Likewise.
	* df-problems.c (df_chain_alloc): Use object_allocator instead of pool_allocator..
	* df-scan.c (struct df_scan_problem_data): Likewise.
	(df_scan_alloc): Likewise.
	* df.h (struct dataflow): Likewise.
	* dse.c (struct read_info_type): Change to type-less pool_allocator.
	(struct insn_info_type): Likewise.
	(struct dse_bb_info_type): Likewise.
	(struct group_info): Likewise.
	(struct deferred_change): Likewise.
	* et-forest.c (struct et_occ): Likewise.
	* et-forest.h (struct et_node): Likewise.
	* ipa-cp.c: Use object_allocator instead of pool_allocator.
	* ipa-inline-analysis.c: Likewise.
	* ipa-profile.c: Likewise.
	* ipa-prop.c: Likewise.
	* ipa-prop.h: Likewise.
	* ira-build.c (initiate_cost_vectors): Change to type-less pool_allocator.
	(ira_allocate_cost_vector): Likewise.
	* ira-color.c (struct update_cost_record): Use object_allocator instead of pool_allocator.
	* lra-int.h (struct lra_live_range): Change to type-less pool_allocator.
	(struct lra_copy): Likewise.
	(struct lra_insn_reg): Likewise.
	* lra-lives.c: Likewise.
	* lra.c: Likewise.
	* regcprop.c (struct queued_debug_insn_change): Use object_allocator instead of pool_allocator.
	* sched-deps.c (sched_deps_init): Likewise.
	* sel-sched-ir.c: Likewise.
	* sel-sched-ir.h: Likewise.
	* stmt.c (expand_case): Likewise.
	(expand_sjlj_dispatch_table): Likewise.
	* tree-sra.c (struct access): Change to type-less pool_allocator.
	(struct assign_link): Likewise.
	* tree-ssa-math-opts.c (pass_cse_reciprocals::execute): Use object_allocator instead of pool_allocator.
	* tree-ssa-pre.c: Likewise.
	* tree-ssa-reassoc.c: Likewise.
	* tree-ssa-sccvn.c (allocate_vn_table): Likewise.
	* tree-ssa-strlen.c: Likewise.
	* tree-ssa-structalias.c: Likewise.
	* var-tracking.c (onepart_pool_allocate): Change to type-less pool_allocator.
	(unshare_variable): Likewise.
	(variable_merge_over_cur): Likewise.
	(variable_from_dropped): Likewise.
	(variable_was_changed): Likewise.
	(set_slot_part): Likewise.
	(emit_notes_for_differences_1): Likewise.
---
 gcc/alloc-pool.h           | 176 +++++++++++++++++++++++++--------------------
 gcc/asan.c                 |   8 +--
 gcc/c-family/c-format.c    |   7 +-
 gcc/cfg.c                  |   5 +-
 gcc/cselib.c               |  17 +++--
 gcc/cselib.h               |  12 ++--
 gcc/df-problems.c          |   2 +-
 gcc/df-scan.c              |  24 +++----
 gcc/df.h                   |   2 +-
 gcc/dse.c                  |  50 +++++++------
 gcc/et-forest.c            |  11 ++-
 gcc/et-forest.h            |   6 +-
 gcc/ipa-cp.c               |   8 +--
 gcc/ipa-inline-analysis.c  |   2 +-
 gcc/ipa-profile.c          |   2 +-
 gcc/ipa-prop.c             |   2 +-
 gcc/ipa-prop.h             |   8 +--
 gcc/ira-build.c            |  18 ++---
 gcc/ira-color.c            |   8 +--
 gcc/lra-int.h              |  19 +++--
 gcc/lra-lives.c            |   3 +-
 gcc/lra.c                  |   4 +-
 gcc/regcprop.c             |   4 +-
 gcc/sched-deps.c           |   8 +--
 gcc/sel-sched-ir.c         |   2 +-
 gcc/sel-sched-ir.h         |   2 +-
 gcc/stmt.c                 |   7 +-
 gcc/tree-sra.c             |  16 ++---
 gcc/tree-ssa-math-opts.c   |   4 +-
 gcc/tree-ssa-pre.c         |   4 +-
 gcc/tree-ssa-reassoc.c     |   2 +-
 gcc/tree-ssa-sccvn.c       |  10 +--
 gcc/tree-ssa-strlen.c      |   3 +-
 gcc/tree-ssa-structalias.c |   4 +-
 gcc/var-tracking.c         |  47 ++++++------
 35 files changed, 270 insertions(+), 237 deletions(-)

diff --git a/gcc/alloc-pool.h b/gcc/alloc-pool.h
index 1785df5..7c78790 100644
--- a/gcc/alloc-pool.h
+++ b/gcc/alloc-pool.h
@@ -25,6 +25,9 @@  extern void dump_alloc_pool_statistics (void);
 
 typedef unsigned long ALLOC_POOL_ID_TYPE;
 
+/* Last used ID.  */
+extern ALLOC_POOL_ID_TYPE last_id;
+
 /* Pool allocator memory usage.  */
 struct pool_usage: public mem_usage
 {
@@ -92,21 +95,18 @@  struct pool_usage: public mem_usage
 
 extern mem_alloc_description<pool_usage> pool_allocator_usage;
 
-/* Type based memory pool allocator.  */
-template <typename T>
+/* Generic pool allocator.  */
 class pool_allocator
 {
 public:
   /* Default constructor for pool allocator called NAME.  Each block
-     has NUM elements.  The allocator support EXTRA_SIZE and can
-     potentially IGNORE_TYPE_SIZE.  */
-  pool_allocator (const char *name, size_t num, size_t extra_size = 0,
-		  bool ignore_type_size = false CXX_MEM_STAT_INFO);
+     has NUM elements.  */
+  pool_allocator (const char *name, size_t num, size_t size CXX_MEM_STAT_INFO);
   ~pool_allocator ();
   void release ();
   void release_if_empty ();
-  T *allocate () ATTRIBUTE_MALLOC;
-  void remove (T *object);
+  void *allocate () ATTRIBUTE_MALLOC;
+  void remove (void *object);
 
 private:
   struct allocation_pool_list
@@ -117,7 +117,6 @@  private:
   /* Initialize a pool allocator.  */
   void initialize ();
 
-  template <typename U>
   struct allocation_object
   {
     /* The ID of alloc pool which the object was allocated from.  */
@@ -136,18 +135,18 @@  private:
 	int64_t align_i;
       } u;
 
-    static inline allocation_object<U> *
+    static inline allocation_object*
     get_instance (void *data_ptr)
     {
-      return (allocation_object<U> *)(((char *)(data_ptr))
-				      - offsetof (allocation_object<U>,
+      return (allocation_object *)(((char *)(data_ptr))
+				      - offsetof (allocation_object,
 						  u.data));
     }
 
-    static inline U *
+    static inline void*
     get_data (void *instance_ptr)
     {
-      return (U*)(((allocation_object<U> *) instance_ptr)->u.data);
+      return (void*)(((allocation_object *) instance_ptr)->u.data);
     }
   };
 
@@ -185,66 +184,33 @@  private:
   size_t m_block_size;
   /* Size of a pool elements in bytes.  */
   size_t m_elt_size;
-  /* Flag if we shoul ignore size of a type.  */
-  bool m_ignore_type_size;
-  /* Extra size in bytes that should be allocated for each element.  */
-  size_t m_extra_size;
+  /* Size in bytes that should be allocated for each element.  */
+  size_t m_size;
   /* Flag if a pool allocator is initialized.  */
   bool m_initialized;
   /* Memory allocation location.  */
   mem_location m_location;
 };
 
-/* Last used ID.  */
-extern ALLOC_POOL_ID_TYPE last_id;
-
-/* Store information about each particular alloc_pool.  Note that this
-   will underestimate the amount the amount of storage used by a small amount:
-   1) The overhead in a pool is not accounted for.
-   2) The unallocated elements in a block are not accounted for.  Note
-   that this can at worst case be one element smaller that the block
-   size for that pool.  */
-struct alloc_pool_descriptor
-{
-  /* Number of pools allocated.  */
-  unsigned long created;
-  /* Gross allocated storage.  */
-  unsigned long allocated;
-  /* Amount of currently active storage.  */
-  unsigned long current;
-  /* Peak amount of storage used.  */
-  unsigned long peak;
-  /* Size of element in the pool.  */
-  int elt_size;
-};
-
-
-/* Hashtable mapping alloc_pool names to descriptors.  */
-extern hash_map<const char *, alloc_pool_descriptor> *alloc_pool_hash;
-
-template <typename T>
 inline
-pool_allocator<T>::pool_allocator (const char *name, size_t num,
-				   size_t extra_size, bool ignore_type_size
-				   MEM_STAT_DECL):
+pool_allocator::pool_allocator (const char *name, size_t num,
+				size_t size MEM_STAT_DECL):
   m_name (name), m_id (0), m_elts_per_block (num), m_returned_free_list (NULL),
   m_virgin_free_list (NULL), m_virgin_elts_remaining (0), m_elts_allocated (0),
   m_elts_free (0), m_blocks_allocated (0), m_block_list (NULL),
-  m_block_size (0), m_ignore_type_size (ignore_type_size),
-  m_extra_size (extra_size), m_initialized (false),
+  m_block_size (0), m_size (size), m_initialized (false),
   m_location (ALLOC_POOL_ORIGIN, false PASS_MEM_STAT) {}
 
 /* Initialize a pool allocator.  */
 
-template <typename T>
-void
-pool_allocator<T>::initialize ()
+inline void
+pool_allocator::initialize ()
 {
   gcc_checking_assert (!m_initialized);
   m_initialized = true;
 
   size_t header_size;
-  size_t size = (m_ignore_type_size ? 0 : sizeof (T)) + m_extra_size;
+  size_t size = m_size;
 
   gcc_checking_assert (m_name);
 
@@ -256,7 +222,7 @@  pool_allocator<T>::initialize ()
   size = align_eight (size);
 
   /* Add the aligned size of ID.  */
-  size += offsetof (allocation_object<T>, u.data);
+  size += offsetof (allocation_object, u.data);
 
   /* Um, we can't really allocate 0 elements per block.  */
   gcc_checking_assert (m_elts_per_block);
@@ -289,9 +255,8 @@  pool_allocator<T>::initialize ()
 }
 
 /* Free all memory allocated for the given memory pool.  */
-template <typename T>
 inline void
-pool_allocator<T>::release ()
+pool_allocator::release ()
 {
   if (!m_initialized)
     return;
@@ -320,24 +285,21 @@  pool_allocator<T>::release ()
   m_block_list = NULL;
 }
 
-template <typename T>
 void
-inline pool_allocator<T>::release_if_empty ()
+inline pool_allocator::release_if_empty ()
 {
   if (m_elts_free == m_elts_allocated)
     release ();
 }
 
-template <typename T>
-inline pool_allocator<T>::~pool_allocator ()
+inline pool_allocator::~pool_allocator ()
 {
   release ();
 }
 
 /* Allocates one element from the pool specified.  */
-template <typename T>
-inline T *
-pool_allocator<T>::allocate ()
+inline void*
+pool_allocator::allocate ()
 {
   if (!m_initialized)
     initialize ();
@@ -353,7 +315,7 @@  pool_allocator<T>::allocate ()
     }
 
 #ifdef ENABLE_VALGRIND_ANNOTATIONS
-  size = m_elt_size - offsetof (allocation_object<T>, u.data);
+  size = m_elt_size - offsetof (allocation_object, u.data);
 #endif
 
   /* If there are no more free elements, make some more!.  */
@@ -387,11 +349,11 @@  pool_allocator<T>::allocate ()
       /* We now know that we can take the first elt off the virgin list and
 	 put it on the returned list.  */
       block = m_virgin_free_list;
-      header = (allocation_pool_list*) allocation_object<T>::get_data (block);
+      header = (allocation_pool_list*) allocation_object::get_data (block);
       header->next = NULL;
 #ifdef ENABLE_CHECKING
       /* Mark the element to be free.  */
-      ((allocation_object<T> *) block)->id = 0;
+      ((allocation_object*) block)->id = 0;
 #endif
       VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS (header,size));
       m_returned_free_list = header;
@@ -408,36 +370,34 @@  pool_allocator<T>::allocate ()
 
 #ifdef ENABLE_CHECKING
   /* Set the ID for element.  */
-  allocation_object<T>::get_instance (header)->id = m_id;
+  allocation_object::get_instance (header)->id = m_id;
 #endif
   VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (header, size));
 
-  /* Call default constructor.  */
-  return (T *)(header);
+  return (void *)(header);
 }
 
 /* Puts PTR back on POOL's free list.  */
-template <typename T>
-void
-pool_allocator<T>::remove (T *object)
+inline void
+pool_allocator::remove (void *object)
 {
   gcc_checking_assert (m_initialized);
 
   allocation_pool_list *header;
   int size ATTRIBUTE_UNUSED;
-  size = m_elt_size - offsetof (allocation_object<T>, u.data);
+  size = m_elt_size - offsetof (allocation_object, u.data);
 
 #ifdef ENABLE_CHECKING
   gcc_assert (object
 	      /* Check if we free more than we allocated, which is Bad (TM).  */
 	      && m_elts_free < m_elts_allocated
 	      /* Check whether the PTR was allocated from POOL.  */
-	      && m_id == allocation_object<T>::get_instance (object)->id);
+	      && m_id == allocation_object::get_instance (object)->id);
 
   memset (object, 0xaf, size);
 
   /* Mark the element to be free.  */
-  allocation_object<T>::get_instance (object)->id = 0;
+  allocation_object::get_instance (object)->id = 0;
 #endif
 
   header = (allocation_pool_list*) object;
@@ -452,4 +412,66 @@  pool_allocator<T>::remove (T *object)
     }
 }
 
+/* Type based memory pool allocator.  */
+template <typename T>
+class object_allocator
+{
+public:
+  /* Default constructor for pool allocator called NAME.  Each block
+     has NUM elements.  */
+  object_allocator (const char *name, size_t num CXX_MEM_STAT_INFO):
+    m_allocator (name, num, sizeof (T) PASS_MEM_STAT) {}
+
+  inline void
+  release ()
+  {
+    m_allocator.release ();
+  }
+
+  inline void release_if_empty ()
+  {
+    m_allocator.release_if_empty ();
+  }
+
+  inline T *
+  allocate () ATTRIBUTE_MALLOC
+  {
+    return ::new (m_allocator.allocate ()) T ();
+  }
+
+  inline void
+  remove (T *object)
+  {
+    m_allocator.remove (object);
+  }
+
+private:
+  pool_allocator m_allocator;
+};
+
+/* Store information about each particular alloc_pool.  Note that this
+   will underestimate the amount the amount of storage used by a small amount:
+   1) The overhead in a pool is not accounted for.
+   2) The unallocated elements in a block are not accounted for.  Note
+   that this can at worst case be one element smaller that the block
+   size for that pool.  */
+struct alloc_pool_descriptor
+{
+  /* Number of pools allocated.  */
+  unsigned long created;
+  /* Gross allocated storage.  */
+  unsigned long allocated;
+  /* Amount of currently active storage.  */
+  unsigned long current;
+  /* Peak amount of storage used.  */
+  unsigned long peak;
+  /* Size of element in the pool.  */
+  int elt_size;
+};
+
+
+/* Hashtable mapping alloc_pool names to descriptors.  */
+extern hash_map<const char *, alloc_pool_descriptor> *alloc_pool_hash;
+
+
 #endif
diff --git a/gcc/asan.c b/gcc/asan.c
index e89817e..dabd6f1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -362,20 +362,20 @@  struct asan_mem_ref
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) asan_mem_ref ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((asan_mem_ref *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<asan_mem_ref> pool;
+  static pool_allocator pool;
 };
 
-pool_allocator<asan_mem_ref> asan_mem_ref::pool ("asan_mem_ref", 10);
+pool_allocator asan_mem_ref::pool ("asan_mem_ref", 10, sizeof (asan_mem_ref));
 
 /* Initializes an instance of asan_mem_ref.  */
 
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 76dc567..2fb1c2e 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -1026,7 +1026,7 @@  static void check_format_info_main (format_check_results *,
 				    function_format_info *,
 				    const char *, int, tree,
 				    unsigned HOST_WIDE_INT,
-				    pool_allocator<format_wanted_type> &);
+				    object_allocator<format_wanted_type> &);
 
 static void init_dollar_format_checking (int, tree);
 static int maybe_read_dollar_number (const char **, int,
@@ -1688,7 +1688,8 @@  check_format_arg (void *ctx, tree format_tree,
      will decrement it if it finds there are extra arguments, but this way
      need not adjust it for every return.  */
   res->number_other++;
-  pool_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool", 10);
+  object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool",
+						  10);
   check_format_info_main (res, info, format_chars, format_length,
 			  params, arg_num, fwt_pool);
 }
@@ -1706,7 +1707,7 @@  check_format_info_main (format_check_results *res,
 			function_format_info *info, const char *format_chars,
 			int format_length, tree params,
 			unsigned HOST_WIDE_INT arg_num,
-			pool_allocator<format_wanted_type> &fwt_pool)
+			object_allocator <format_wanted_type> &fwt_pool)
 {
   const char *orig_format_chars = format_chars;
   tree first_fillin_param = params;
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 72f711c..a671956 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -1052,15 +1052,14 @@  static hash_table<bb_copy_hasher> *bb_copy;
 
 /* And between loops and copies.  */
 static hash_table<bb_copy_hasher> *loop_copy;
-static pool_allocator<htab_bb_copy_original_entry> *original_copy_bb_pool;
+static object_allocator<htab_bb_copy_original_entry> *original_copy_bb_pool;
 
 /* Initialize the data structures to maintain mapping between blocks
    and its copies.  */
 void
 initialize_original_copy_tables (void)
 {
-
-  original_copy_bb_pool = new pool_allocator<htab_bb_copy_original_entry>
+  original_copy_bb_pool = new object_allocator<htab_bb_copy_original_entry>
     ("original_copy", 10);
   bb_original = new hash_table<bb_copy_hasher> (10);
   bb_copy = new hash_table<bb_copy_hasher> (10);
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 6336e6b..1931a3e 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -54,17 +54,17 @@  struct elt_list
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) elt_list ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((elt_list *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<elt_list> pool;
+  static pool_allocator pool;
 };
 
 static bool cselib_record_memory;
@@ -267,12 +267,11 @@  static unsigned int cfa_base_preserved_regno = INVALID_REGNUM;
    each time memory is invalidated.  */
 static cselib_val *first_containing_mem = &dummy_val;
 
-pool_allocator<elt_list> elt_list::pool ("elt_list", 10);
-pool_allocator<elt_loc_list> elt_loc_list::pool ("elt_loc_list", 10);
-pool_allocator<cselib_val> cselib_val::pool ("cselib_val_list", 10);
+pool_allocator elt_list::pool ("elt_list", 10, sizeof (elt_list));
+pool_allocator elt_loc_list::pool ("elt_loc_list", 10, sizeof (elt_loc_list));
+pool_allocator cselib_val::pool ("cselib_val_list", 10, sizeof (cselib_val));
 
-static pool_allocator<rtx_def> value_pool ("value", 100, RTX_CODE_SIZE (VALUE),
-					   true);
+static pool_allocator value_pool ("value", 100, RTX_CODE_SIZE (VALUE));
 
 /* If nonnull, cselib will call this function before freeing useless
    VALUEs.  A VALUE is deemed useless if its "locs" field is null.  */
@@ -1329,7 +1328,7 @@  new_cselib_val (unsigned int hash, machine_mode mode, rtx x)
      precisely when we can have VALUE RTXen (when cselib is active)
      so we don't need to put them in garbage collected memory.
      ??? Why should a VALUE be an RTX in the first place?  */
-  e->val_rtx = value_pool.allocate ();
+  e->val_rtx = (rtx_def*) value_pool.allocate ();
   memset (e->val_rtx, 0, RTX_HDR_SIZE);
   PUT_CODE (e->val_rtx, VALUE);
   PUT_MODE (e->val_rtx, mode);
diff --git a/gcc/cselib.h b/gcc/cselib.h
index cdd06ad..171d827 100644
--- a/gcc/cselib.h
+++ b/gcc/cselib.h
@@ -45,17 +45,17 @@  struct cselib_val
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) cselib_val ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((cselib_val *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<cselib_val> pool;
+  static pool_allocator pool;
 };
 
 /* A list of rtl expressions that hold the same value.  */
@@ -70,17 +70,17 @@  struct elt_loc_list {
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) elt_loc_list ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((elt_loc_list *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<elt_loc_list> pool;
+  static pool_allocator pool;
 };
 
 /* Describe a single set that is part of an insn.  */
diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index a345781..2ad97f5 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -2005,7 +2005,7 @@  static void
 df_chain_alloc (bitmap all_blocks ATTRIBUTE_UNUSED)
 {
   df_chain_remove_problem ();
-  df_chain->block_pool = new pool_allocator<df_link> ("df_chain_block pool",
+  df_chain->block_pool = new object_allocator<df_link> ("df_chain_block pool",
 						      50);
   df_chain->optional_p = true;
 }
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 4e53f88..55c64a2 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -154,12 +154,12 @@  static const unsigned int copy_all = copy_defs | copy_uses | copy_eq_uses
 /* Problem data for the scanning dataflow function.  */
 struct df_scan_problem_data
 {
-  pool_allocator<df_base_ref> *ref_base_pool;
-  pool_allocator<df_artificial_ref> *ref_artificial_pool;
-  pool_allocator<df_regular_ref> *ref_regular_pool;
-  pool_allocator<df_insn_info> *insn_pool;
-  pool_allocator<df_reg_info> *reg_pool;
-  pool_allocator<df_mw_hardreg> *mw_reg_pool;
+  object_allocator<df_base_ref> *ref_base_pool;
+  object_allocator<df_artificial_ref> *ref_artificial_pool;
+  object_allocator<df_regular_ref> *ref_regular_pool;
+  object_allocator<df_insn_info> *insn_pool;
+  object_allocator<df_reg_info> *reg_pool;
+  object_allocator<df_mw_hardreg> *mw_reg_pool;
 
   bitmap_obstack reg_bitmaps;
   bitmap_obstack insn_bitmaps;
@@ -268,17 +268,17 @@  df_scan_alloc (bitmap all_blocks ATTRIBUTE_UNUSED)
   df_scan->problem_data = problem_data;
   df_scan->computed = true;
 
-  problem_data->ref_base_pool = new pool_allocator<df_base_ref>
+  problem_data->ref_base_pool = new object_allocator<df_base_ref>
     ("df_scan ref base", SCAN_PROBLEM_DATA_BLOCK_SIZE);
-  problem_data->ref_artificial_pool = new pool_allocator<df_artificial_ref>
+  problem_data->ref_artificial_pool = new object_allocator<df_artificial_ref>
     ("df_scan ref artificial", SCAN_PROBLEM_DATA_BLOCK_SIZE);
-  problem_data->ref_regular_pool = new pool_allocator<df_regular_ref>
+  problem_data->ref_regular_pool = new object_allocator<df_regular_ref>
     ("df_scan ref regular", SCAN_PROBLEM_DATA_BLOCK_SIZE);
-  problem_data->insn_pool = new pool_allocator<df_insn_info>
+  problem_data->insn_pool = new object_allocator<df_insn_info>
     ("df_scan insn", SCAN_PROBLEM_DATA_BLOCK_SIZE);
-  problem_data->reg_pool = new pool_allocator<df_reg_info>
+  problem_data->reg_pool = new object_allocator<df_reg_info>
     ("df_scan reg", SCAN_PROBLEM_DATA_BLOCK_SIZE);
-  problem_data->mw_reg_pool = new pool_allocator<df_mw_hardreg>
+  problem_data->mw_reg_pool = new object_allocator<df_mw_hardreg>
     ("df_scan mw_reg", SCAN_PROBLEM_DATA_BLOCK_SIZE / 16);
 
   bitmap_obstack_initialize (&problem_data->reg_bitmaps);
diff --git a/gcc/df.h b/gcc/df.h
index 7023c9a..e1ffea3 100644
--- a/gcc/df.h
+++ b/gcc/df.h
@@ -300,7 +300,7 @@  struct dataflow
   unsigned int block_info_size;
 
   /* The pool to allocate the block_info from. */
-  pool_allocator<df_link> *block_pool;
+  object_allocator<df_link> *block_pool;
 
   /* The lr and live problems have their transfer functions recomputed
      only if necessary.  This is possible for them because, the
diff --git a/gcc/dse.c b/gcc/dse.c
index 508ec00..ecfc38d 100644
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -316,10 +316,10 @@  lowpart_bitmask (int n)
 }
 
 typedef struct store_info *store_info_t;
-static pool_allocator<store_info> cse_store_info_pool ("cse_store_info_pool",
+static object_allocator<store_info> cse_store_info_pool ("cse_store_info_pool",
 						       100);
 
-static pool_allocator<store_info> rtx_store_info_pool ("rtx_store_info_pool",
+static object_allocator<store_info> rtx_store_info_pool ("rtx_store_info_pool",
 						       100);
 
 /* This structure holds information about a load.  These are only
@@ -346,21 +346,22 @@  struct read_info_type
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) read_info_type ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((read_info_type *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<read_info_type> pool;
+  static pool_allocator pool;
 };
 typedef struct read_info_type *read_info_t;
 
-pool_allocator<read_info_type> read_info_type::pool ("read_info_pool", 100);
+pool_allocator read_info_type::pool ("read_info_pool", 100,
+				     sizeof (read_info_type));
 
 /* One of these records is created for each insn.  */
 
@@ -450,21 +451,22 @@  struct insn_info_type
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) insn_info_type ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((insn_info_type *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<insn_info_type> pool;
+  static pool_allocator pool;
 };
 typedef struct insn_info_type *insn_info_t;
 
-pool_allocator<insn_info_type> insn_info_type::pool ("insn_info_pool", 100);
+pool_allocator insn_info_type::pool ("insn_info_pool", 100,
+				     sizeof (insn_info_type));
 
 /* The linked list of stores that are under consideration in this
    basic block.  */
@@ -530,21 +532,22 @@  struct dse_bb_info_type
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) dse_bb_info_type ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((dse_bb_info_type *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<dse_bb_info_type> pool;
+  static pool_allocator pool;
 };
 
 typedef struct dse_bb_info_type *bb_info_t;
-pool_allocator<dse_bb_info_type> dse_bb_info_type::pool ("bb_info_pool", 100);
+pool_allocator dse_bb_info_type::pool ("bb_info_pool", 100,
+				       sizeof (dse_bb_info_type));
 
 /* Table to hold all bb_infos.  */
 static bb_info_t *bb_table;
@@ -616,22 +619,23 @@  struct group_info
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) group_info ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((group_info *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<group_info> pool;
+  static pool_allocator pool;
 };
 typedef struct group_info *group_info_t;
 typedef const struct group_info *const_group_info_t;
 
-pool_allocator<group_info> group_info::pool ("rtx_group_info_pool", 100);
+pool_allocator group_info::pool ("rtx_group_info_pool", 100,
+				 sizeof (group_info));
 
 /* Index into the rtx_group_vec.  */
 static int rtx_group_next_id;
@@ -656,23 +660,23 @@  struct deferred_change
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) deferred_change ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((deferred_change *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<deferred_change> pool;
+  static pool_allocator pool;
 };
 
 typedef struct deferred_change *deferred_change_t;
 
-pool_allocator<deferred_change> deferred_change::pool
-  ("deferred_change_pool", 10);
+pool_allocator deferred_change::pool
+  ("deferred_change_pool", 10, sizeof (deferred_change));
 
 static deferred_change_t deferred_change_list = NULL;
 
diff --git a/gcc/et-forest.c b/gcc/et-forest.c
index a3f60d3..d127289 100644
--- a/gcc/et-forest.c
+++ b/gcc/et-forest.c
@@ -58,22 +58,21 @@  struct et_occ
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) et_occ ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((et_occ *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<et_occ> pool;
-
+  static pool_allocator pool;
 };
 
-pool_allocator<et_node> et_node::pool ("et_nodes pool", 300);
-pool_allocator<et_occ> et_occ::pool ("et_occ pool", 300);
+pool_allocator et_node::pool ("et_nodes pool", 300, sizeof (et_node));
+pool_allocator et_occ::pool ("et_occ pool", 300, sizeof (et_occ));
 
 /* Changes depth of OCC to D.  */
 
diff --git a/gcc/et-forest.h b/gcc/et-forest.h
index 15c582d..e076555 100644
--- a/gcc/et-forest.h
+++ b/gcc/et-forest.h
@@ -70,17 +70,17 @@  struct et_node
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) et_node ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((et_node *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<et_node> pool;
+  static pool_allocator pool;
 };
 
 struct et_node *et_new_tree (void *data);
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index b87c984..591f409 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -281,16 +281,16 @@  public:
 
 /* Allocation pools for values and their sources in ipa-cp.  */
 
-pool_allocator<ipcp_value<tree> > ipcp_cst_values_pool
+object_allocator<ipcp_value<tree> > ipcp_cst_values_pool
   ("IPA-CP constant values", 32);
 
-pool_allocator<ipcp_value<ipa_polymorphic_call_context> >
+object_allocator<ipcp_value<ipa_polymorphic_call_context> >
   ipcp_poly_ctx_values_pool ("IPA-CP polymorphic contexts", 32);
 
-pool_allocator<ipcp_value_source<tree> > ipcp_sources_pool
+object_allocator<ipcp_value_source<tree> > ipcp_sources_pool
   ("IPA-CP value sources", 64);
 
-pool_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool
+object_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool
   ("IPA_CP aggregate lattices", 32);
 
 /* Maximal count found in program.  */
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index d062d7a..ad849c5 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -159,7 +159,7 @@  vec<inline_edge_summary_t> inline_edge_summary_vec;
 vec<edge_growth_cache_entry> edge_growth_cache;
 
 /* Edge predicates goes here.  */
-static pool_allocator<predicate> edge_predicate_pool ("edge predicates", 10);
+static object_allocator<predicate> edge_predicate_pool ("edge predicates", 10);
 
 /* Return true predicate (tautology).
    We represent it by empty list of clauses.  */
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index 3de4ec5..6da9b71 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -97,7 +97,7 @@  struct histogram_entry
    duplicate entries.  */
 
 vec<histogram_entry *> histogram;
-static pool_allocator<histogram_entry> histogram_pool
+static object_allocator<histogram_entry> histogram_pool
   ("IPA histogram", 10);
 
 /* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR.  */
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index cf3fa4e..0038921 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -163,7 +163,7 @@  struct ipa_cst_ref_desc
 
 /* Allocation pool for reference descriptions.  */
 
-static pool_allocator<ipa_cst_ref_desc> ipa_refdesc_pool
+static object_allocator<ipa_cst_ref_desc> ipa_refdesc_pool
   ("IPA-PROP ref descriptions", 32);
 
 /* Return true if DECL_FUNCTION_SPECIFIC_OPTIMIZATION of the decl associated
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index e6725aa..47790e5 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -598,18 +598,18 @@  void ipcp_verify_propagated_values (void);
 template <typename value>
 class ipcp_value;
 
-extern pool_allocator<ipcp_value<tree> > ipcp_cst_values_pool;
-extern pool_allocator<ipcp_value<ipa_polymorphic_call_context> >
+extern object_allocator<ipcp_value<tree> > ipcp_cst_values_pool;
+extern object_allocator<ipcp_value<ipa_polymorphic_call_context> >
   ipcp_poly_ctx_values_pool;
 
 template <typename valtype>
 class ipcp_value_source;
 
-extern pool_allocator<ipcp_value_source<tree> > ipcp_sources_pool;
+extern object_allocator<ipcp_value_source<tree> > ipcp_sources_pool;
 
 class ipcp_agg_lattice;
 
-extern pool_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool;
+extern object_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool;
 
 /* Operation to be performed for the parameter in ipa_parm_adjustment
    below.  */
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 9fcbcb0..6706a00 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -423,9 +423,9 @@  rebuild_regno_allocno_maps (void)
 
 
 /* Pools for allocnos, allocno live ranges and objects.  */
-static pool_allocator<live_range> live_range_pool ("live ranges", 100);
-static pool_allocator<ira_allocno> allocno_pool ("allocnos", 100);
-static pool_allocator<ira_object> object_pool ("objects", 100);
+static object_allocator<live_range> live_range_pool ("live ranges", 100);
+static object_allocator<ira_allocno> allocno_pool ("allocnos", 100);
+static object_allocator<ira_object> object_pool ("objects", 100);
 
 /* Vec containing references to all created allocnos.  It is a
    container of array allocnos.  */
@@ -1173,7 +1173,7 @@  finish_allocnos (void)
 
 
 /* Pools for allocno preferences.  */
-static pool_allocator <ira_allocno_pref> pref_pool ("prefs", 100);
+static object_allocator <ira_allocno_pref> pref_pool ("prefs", 100);
 
 /* Vec containing references to all created preferences.  It is a
    container of array ira_prefs.  */
@@ -1360,7 +1360,7 @@  finish_prefs (void)
 
 
 /* Pools for copies.  */
-static pool_allocator<ira_allocno_copy> copy_pool ("copies", 100);
+static object_allocator<ira_allocno_copy> copy_pool ("copies", 100);
 
 /* Vec containing references to all created copies.  It is a
    container of array ira_copies.  */
@@ -1619,7 +1619,7 @@  finish_copies (void)
 
 
 /* Pools for cost vectors.  It is defined only for allocno classes.  */
-static pool_allocator<int> * cost_vector_pool[N_REG_CLASSES];
+static pool_allocator *cost_vector_pool[N_REG_CLASSES];
 
 /* The function initiates work with hard register cost vectors.  It
    creates allocation pool for each allocno class.  */
@@ -1632,9 +1632,9 @@  initiate_cost_vectors (void)
   for (i = 0; i < ira_allocno_classes_num; i++)
     {
       aclass = ira_allocno_classes[i];
-      cost_vector_pool[aclass] = new pool_allocator<int>
+      cost_vector_pool[aclass] = new pool_allocator
 	("cost vectors", 100,
-	 sizeof (int) * (ira_class_hard_regs_num[aclass] - 1));
+	 sizeof (int) * (ira_class_hard_regs_num[aclass]));
     }
 }
 
@@ -1642,7 +1642,7 @@  initiate_cost_vectors (void)
 int *
 ira_allocate_cost_vector (reg_class_t aclass)
 {
-  return cost_vector_pool[(int) aclass]->allocate ();
+  return (int*) cost_vector_pool[(int) aclass]->allocate ();
 }
 
 /* Free a cost vector VEC for ACLASS.  */
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index 6c53507..f152aeb 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -115,17 +115,17 @@  struct update_cost_record
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) update_cost_record ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((update_cost_record *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<update_cost_record> pool;
+  static pool_allocator pool;
 };
 
 /* To decrease footprint of ira_allocno structure we store all data
@@ -1169,7 +1169,7 @@  setup_profitable_hard_regs (void)
    allocnos.  */
 
 /* Pool for update cost records.  */
-static pool_allocator<update_cost_record> update_cost_record_pool
+static object_allocator<update_cost_record> update_cost_record_pool
   ("update cost records", 100);
 
 /* Return new update cost record with given params.  */
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 25bd3ce..8a10a79 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -58,17 +58,17 @@  struct lra_live_range
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) lra_live_range ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((lra_live_range *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<lra_live_range> pool;
+  static pool_allocator pool;
 };
 
 typedef struct lra_copy *lra_copy_t;
@@ -88,18 +88,17 @@  struct lra_copy
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) lra_copy ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((lra_copy *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<lra_copy> pool;
-
+  static pool_allocator pool;
 };
 
 /* Common info about a register (pseudo or hard register).  */
@@ -211,17 +210,17 @@  struct lra_insn_reg
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) lra_insn_reg ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((lra_insn_reg *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<lra_insn_reg> pool;
+  static pool_allocator pool;
 };
 
 /* Static part (common info for insns with the same ICODE) of LRA
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c
index 5157c85..8fdf2fb 100644
--- a/gcc/lra-lives.c
+++ b/gcc/lra-lives.c
@@ -110,7 +110,8 @@  static sparseset unused_set, dead_set;
 static bitmap_head temp_bitmap;
 
 /* Pool for pseudo live ranges.	 */
-pool_allocator <lra_live_range> lra_live_range::pool ("live ranges", 100);
+pool_allocator lra_live_range::pool ("live ranges", 100,
+				     sizeof (lra_live_range));
 
 /* Free live range list LR.  */
 static void
diff --git a/gcc/lra.c b/gcc/lra.c
index 5d1f429..2ca4727 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -537,7 +537,7 @@  lra_update_dups (lra_insn_recog_data_t id, signed char *nops)
    insns.  */
 
 /* Pools for insn reg info.  */
-pool_allocator<lra_insn_reg> lra_insn_reg::pool ("insn regs", 100);
+pool_allocator lra_insn_reg::pool ("insn regs", 100, sizeof (lra_insn_reg));
 
 /* Create LRA insn related info about a reference to REGNO in INSN with
    TYPE (in/out/inout), biggest reference mode MODE, flag that it is
@@ -1281,7 +1281,7 @@  get_new_reg_value (void)
 }
 
 /* Pools for copies.  */
-pool_allocator<lra_copy> lra_copy::pool ("lra copies", 100);
+pool_allocator lra_copy::pool ("lra copies", 100, sizeof (lra_copy));
 
 /* Vec referring to pseudo copies.  */
 static vec<lra_copy_t> copy_vec;
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index cca495e..0ffe32b 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -72,7 +72,7 @@  struct queued_debug_insn_change
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<queued_debug_insn_change> pool;
+  static object_allocator<queued_debug_insn_change> pool;
 };
 
 /* For each register, we have a list of registers that contain the same
@@ -96,7 +96,7 @@  struct value_data
   unsigned int n_debug_insn_changes;
 };
 
-pool_allocator<queued_debug_insn_change> queued_debug_insn_change::pool
+object_allocator<queued_debug_insn_change> queued_debug_insn_change::pool
   ("debug insn changes pool", 256);
 
 static bool skip_debug_insn_p;
diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c
index b62dc00..b842df8 100644
--- a/gcc/sched-deps.c
+++ b/gcc/sched-deps.c
@@ -327,7 +327,7 @@  dep_link_is_detached_p (dep_link_t link)
 }
 
 /* Pool to hold all dependency nodes (dep_node_t).  */
-static pool_allocator<_dep_node> *dn_pool;
+static object_allocator<_dep_node> *dn_pool;
 
 /* Number of dep_nodes out there.  */
 static int dn_pool_diff = 0;
@@ -368,7 +368,7 @@  delete_dep_node (dep_node_t n)
 }
 
 /* Pool to hold dependencies lists (deps_list_t).  */
-static pool_allocator<_deps_list> *dl_pool;
+static object_allocator<_deps_list> *dl_pool;
 
 /* Number of deps_lists out there.  */
 static int dl_pool_diff = 0;
@@ -4065,10 +4065,10 @@  sched_deps_init (bool global_p)
 
   if (global_p)
     {
-      dl_pool = new pool_allocator<_deps_list> ("deps_list",
+      dl_pool = new object_allocator<_deps_list> ("deps_list",
                                    /* Allocate lists for one block at a time.  */
                                    insns_in_block);
-      dn_pool = new pool_allocator<_dep_node> ("dep_node",
+      dn_pool = new object_allocator<_dep_node> ("dep_node",
                                    /* Allocate nodes for one block at a time.
                                       We assume that average insn has
                                       5 producers.  */
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index f9b7655..828bc66 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -62,7 +62,7 @@  vec<sel_region_bb_info_def>
     sel_region_bb_info = vNULL;
 
 /* A pool for allocating all lists.  */
-pool_allocator<_list_node> sched_lists_pool ("sel-sched-lists", 500);
+object_allocator<_list_node> sched_lists_pool ("sel-sched-lists", 500);
 
 /* This contains information about successors for compute_av_set.  */
 struct succs_info current_succs;
diff --git a/gcc/sel-sched-ir.h b/gcc/sel-sched-ir.h
index 30d3fd8..52d87f8 100644
--- a/gcc/sel-sched-ir.h
+++ b/gcc/sel-sched-ir.h
@@ -363,7 +363,7 @@  struct _list_node
 /* _list_t functions.
    All of _*list_* functions are used through accessor macros, thus
    we can't move them in sel-sched-ir.c.  */
-extern pool_allocator<_list_node> sched_lists_pool;
+extern object_allocator<_list_node> sched_lists_pool;
 
 static inline _list_t
 _list_alloc (void)
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 7c40e12..152122c 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -736,7 +736,8 @@  do_jump_if_equal (machine_mode mode, rtx op0, rtx op1, rtx_code_label *label,
 
 static struct case_node *
 add_case_node (struct case_node *head, tree low, tree high,
-	       tree label, int prob, pool_allocator<case_node> &case_node_pool)
+	       tree label, int prob,
+	       object_allocator<case_node> &case_node_pool)
 {
   struct case_node *r;
 
@@ -1148,7 +1149,7 @@  expand_case (gswitch *stmt)
   struct case_node *case_list = 0;
 
   /* A pool for case nodes.  */
-  pool_allocator<case_node> case_node_pool ("struct case_node pool", 100);
+  object_allocator<case_node> case_node_pool ("struct case_node pool", 100);
 
   /* An ERROR_MARK occurs for various reasons including invalid data type.
      ??? Can this still happen, with GIMPLE and all?  */
@@ -1324,7 +1325,7 @@  expand_sjlj_dispatch_table (rtx dispatch_index,
     {
       /* Similar to expand_case, but much simpler.  */
       struct case_node *case_list = 0;
-      pool_allocator<case_node> case_node_pool ("struct sjlj_case pool",
+      object_allocator<case_node> case_node_pool ("struct sjlj_case pool",
 						ncases);
       tree index_expr = make_tree (index_type, dispatch_index);
       tree minval = build_int_cst (index_type, 0);
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 8e34244..42efecf 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -290,24 +290,24 @@  struct access
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) access ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((access *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<access> pool;
+  static pool_allocator pool;
 };
 
 typedef struct access *access_p;
 
 
 /* Alloc pool for allocating access structures.  */
-pool_allocator<struct access> access::pool ("SRA accesses", 16);
+pool_allocator access::pool ("SRA accesses", 16, sizeof (access));
 
 /* A structure linking lhs and rhs accesses from an aggregate assignment.  They
    are used to propagate subaccesses from rhs to lhs as long as they don't
@@ -320,21 +320,21 @@  struct assign_link
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
-    return pool.allocate ();
+    return ::new (pool.allocate ()) assign_link ();
   }
 
   /* Delete operator utilizing pool allocation.  */
   inline void operator delete (void *ptr)
   {
-    pool.remove ((assign_link *) ptr);
+    pool.remove (ptr);
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<assign_link> pool;
+  static pool_allocator pool;
 };
 
 /* Alloc pool for allocating assign link structures.  */
-pool_allocator<assign_link> assign_link::pool ("SRA links", 16);
+pool_allocator assign_link::pool ("SRA links", 16, sizeof (assign_link));
 
 /* Base (tree) -> Vector (vec<access_p> *) map.  */
 static hash_map<tree, auto_vec<access_p> > *base_access_vec;
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 96361a6..0cd75a7 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -217,7 +217,7 @@  static struct
 static struct occurrence *occ_head;
 
 /* Allocation pool for getting instances of "struct occurrence".  */
-static pool_allocator<occurrence> *occ_pool;
+static object_allocator<occurrence> *occ_pool;
 
 
 
@@ -560,7 +560,7 @@  pass_cse_reciprocals::execute (function *fun)
   basic_block bb;
   tree arg;
 
-  occ_pool = new pool_allocator<occurrence>
+  occ_pool = new object_allocator<occurrence>
     ("dominators for recip", n_basic_blocks_for_fn (fun) / 3 + 1);
 
   memset (&reciprocal_stats, 0, sizeof (reciprocal_stats));
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index e8a670e..579b2c5 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -366,7 +366,7 @@  clear_expression_ids (void)
   expressions.release ();
 }
 
-static pool_allocator<pre_expr_d> pre_expr_pool ("pre_expr nodes", 30);
+static object_allocator<pre_expr_d> pre_expr_pool ("pre_expr nodes", 30);
 
 /* Given an SSA_NAME NAME, get or create a pre_expr to represent it.  */
 
@@ -505,7 +505,7 @@  static unsigned int get_expr_value_id (pre_expr);
 /* We can add and remove elements and entries to and from sets
    and hash tables, so we use alloc pools for them.  */
 
-static pool_allocator<bitmap_set> bitmap_set_pool ("Bitmap sets", 30);
+static object_allocator<bitmap_set> bitmap_set_pool ("Bitmap sets", 30);
 static bitmap_obstack grand_bitmap_obstack;
 
 /* Set of blocks with statements that have had their EH properties changed.  */
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 3eb098e..bacc16d 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -221,7 +221,7 @@  typedef struct operand_entry
   unsigned int count;
 } *operand_entry_t;
 
-static pool_allocator<operand_entry> operand_entry_pool ("operand entry pool",
+static object_allocator<operand_entry> operand_entry_pool ("operand entry pool",
 							 30);
 
 /* This is used to assign a unique ID to each struct operand_entry
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index ccfa6b6..529234b 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -280,8 +280,8 @@  typedef struct vn_tables_s
   vn_phi_table_type *phis;
   vn_reference_table_type *references;
   struct obstack nary_obstack;
-  pool_allocator<vn_phi_s> *phis_pool;
-  pool_allocator<vn_reference_s> *references_pool;
+  object_allocator<vn_phi_s> *phis_pool;
+  object_allocator<vn_reference_s> *references_pool;
 } *vn_tables_t;
 
 
@@ -4147,9 +4147,9 @@  allocate_vn_table (vn_tables_t table)
   table->references = new vn_reference_table_type (23);
 
   gcc_obstack_init (&table->nary_obstack);
-  table->phis_pool = new pool_allocator<vn_phi_s> ("VN phis", 30);
-  table->references_pool = new pool_allocator<vn_reference_s> ("VN references",
-							       30);
+  table->phis_pool = new object_allocator<vn_phi_s> ("VN phis", 30);
+  table->references_pool = new object_allocator<vn_reference_s>
+    ("VN references", 30);
 }
 
 /* Free a value number table.  */
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index fc848ea..9e96db8 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -128,7 +128,8 @@  typedef struct strinfo_struct
 } *strinfo;
 
 /* Pool for allocating strinfo_struct entries.  */
-static pool_allocator<strinfo_struct> strinfo_pool ("strinfo_struct pool", 64);
+static object_allocator<strinfo_struct> strinfo_pool ("strinfo_struct pool",
+						      64);
 
 /* Vector mapping positive string indexes to strinfo, for the
    current basic block.  The first pointer in the vector is special,
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index cef73fa..7e0cb9b 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -340,7 +340,7 @@  static varinfo_t lookup_vi_for_tree (tree);
 static inline bool type_can_have_subvars (const_tree);
 
 /* Pool of variable info structures.  */
-static pool_allocator<variable_info> variable_info_pool
+static object_allocator<variable_info> variable_info_pool
   ("Variable info pool", 30);
 
 /* Map varinfo to final pt_solution.  */
@@ -541,7 +541,7 @@  struct constraint
 /* List of constraints that we use to build the constraint graph from.  */
 
 static vec<constraint_t> constraints;
-static pool_allocator<constraint> constraint_pool ("Constraint pool", 30);
+static object_allocator<constraint> constraint_pool ("Constraint pool", 30);
 
 /* The constraint graph is represented as an array of bitmaps
    containing successor nodes.  */
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index dbf090e..e922c19 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -283,7 +283,7 @@  typedef struct attrs_def
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<attrs_def> pool;
+  static object_allocator<attrs_def> pool;
 } *attrs;
 
 /* Structure for chaining the locations.  */
@@ -314,7 +314,7 @@  typedef struct location_chain_def
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<location_chain_def> pool;
+  static object_allocator<location_chain_def> pool;
 } *location_chain;
 
 /* A vector of loc_exp_dep holds the active dependencies of a one-part
@@ -346,7 +346,7 @@  typedef struct loc_exp_dep_s
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<loc_exp_dep_s> pool;
+  static object_allocator<loc_exp_dep_s> pool;
 } loc_exp_dep;
 
 
@@ -600,7 +600,7 @@  typedef struct shared_hash_def
   }
 
   /* Memory allocation pool.  */
-  static pool_allocator<shared_hash_def> pool;
+  static object_allocator<shared_hash_def> pool;
 } *shared_hash;
 
 /* Structure holding the IN or OUT set for a basic block.  */
@@ -645,28 +645,28 @@  typedef struct variable_tracking_info_def
 } *variable_tracking_info;
 
 /* Alloc pool for struct attrs_def.  */
-pool_allocator<attrs_def> attrs_def::pool ("attrs_def pool", 1024);
+object_allocator<attrs_def> attrs_def::pool ("attrs_def pool", 1024);
 
 /* Alloc pool for struct variable_def with MAX_VAR_PARTS entries.  */
 
-static pool_allocator<variable_def> var_pool
-  ("variable_def pool", 64,
+static pool_allocator var_pool
+  ("variable_def pool", 64, sizeof (variable_def) +
    (MAX_VAR_PARTS - 1) * sizeof (((variable)NULL)->var_part[0]));
 
 /* Alloc pool for struct variable_def with a single var_part entry.  */
-static pool_allocator<variable_def> valvar_pool
-  ("small variable_def pool", 256);
+static pool_allocator valvar_pool
+  ("small variable_def pool", 256, sizeof (variable_def));
 
 /* Alloc pool for struct location_chain_def.  */
-pool_allocator<location_chain_def> location_chain_def::pool
+object_allocator<location_chain_def> location_chain_def::pool
   ("location_chain_def pool", 1024);
 
 /* Alloc pool for struct shared_hash_def.  */
-pool_allocator<shared_hash_def> shared_hash_def::pool
+object_allocator<shared_hash_def> shared_hash_def::pool
   ("shared_hash_def pool", 256);
 
 /* Alloc pool for struct loc_exp_dep_s for NOT_ONEPART variables.  */
-pool_allocator<loc_exp_dep> loc_exp_dep::pool ("loc_exp_dep pool", 64);
+object_allocator<loc_exp_dep> loc_exp_dep::pool ("loc_exp_dep pool", 64);
 
 /* Changed variables, notes will be emitted for them.  */
 static variable_table_type *changed_variables;
@@ -1427,12 +1427,19 @@  dv_onepart_p (decl_or_value dv)
 }
 
 /* Return the variable pool to be used for a dv of type ONEPART.  */
-static inline pool_allocator <variable_def> &
+static inline pool_allocator &
 onepart_pool (onepart_enum_t onepart)
 {
   return onepart ? valvar_pool : var_pool;
 }
 
+/* Allocate a variable_def from the corresponding variable pool.  */
+static inline variable_def *
+onepart_pool_allocate (onepart_enum_t onepart)
+{
+  return (variable_def*) onepart_pool (onepart).allocate ();
+}
+
 /* Build a decl_or_value out of a decl.  */
 static inline decl_or_value
 dv_from_decl (tree decl)
@@ -1787,7 +1794,7 @@  unshare_variable (dataflow_set *set, variable_def **slot, variable var,
   variable new_var;
   int i;
 
-  new_var = onepart_pool (var->onepart).allocate ();
+  new_var = onepart_pool_allocate (var->onepart);
   new_var->dv = var->dv;
   new_var->refcount = 1;
   var->refcount--;
@@ -4065,7 +4072,7 @@  variable_merge_over_cur (variable s1var, struct dfset_merge *dsm)
 	{
 	  if (node)
 	    {
-	      dvar = onepart_pool (onepart).allocate ();
+	      dvar = onepart_pool_allocate (onepart);
 	      dvar->dv = dv;
 	      dvar->refcount = 1;
 	      dvar->n_var_parts = 1;
@@ -4201,7 +4208,7 @@  variable_merge_over_cur (variable s1var, struct dfset_merge *dsm)
 							  INSERT);
 		  if (!*slot)
 		    {
-		      variable var = onepart_pool (ONEPART_VALUE).allocate ();
+		      variable var = onepart_pool_allocate (ONEPART_VALUE);
 		      var->dv = dv;
 		      var->refcount = 1;
 		      var->n_var_parts = 1;
@@ -7350,7 +7357,7 @@  variable_from_dropped (decl_or_value dv, enum insert_option insert)
 
   gcc_checking_assert (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR);
 
-  empty_var = onepart_pool (onepart).allocate ();
+  empty_var = onepart_pool_allocate (onepart);
   empty_var->dv = dv;
   empty_var->refcount = 1;
   empty_var->n_var_parts = 0;
@@ -7454,7 +7461,7 @@  variable_was_changed (variable var, dataflow_set *set)
 
 	  if (!empty_var)
 	    {
-	      empty_var = onepart_pool (onepart).allocate ();
+	      empty_var = onepart_pool_allocate (onepart);
 	      empty_var->dv = var->dv;
 	      empty_var->refcount = 1;
 	      empty_var->n_var_parts = 0;
@@ -7578,7 +7585,7 @@  set_slot_part (dataflow_set *set, rtx loc, variable_def **slot,
   if (!var)
     {
       /* Create new variable information.  */
-      var = onepart_pool (onepart).allocate ();
+      var = onepart_pool_allocate (onepart);
       var->dv = dv;
       var->refcount = 1;
       var->n_var_parts = 1;
@@ -9058,7 +9065,7 @@  emit_notes_for_differences_1 (variable_def **slot, variable_table_type *new_vars
 
       if (!empty_var)
 	{
-	  empty_var = onepart_pool (old_var->onepart).allocate ();
+	  empty_var = onepart_pool_allocate (old_var->onepart);
 	  empty_var->dv = old_var->dv;
 	  empty_var->refcount = 0;
 	  empty_var->n_var_parts = 0;
-- 
2.1.4