From patchwork Wed Jul 16 08:04:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Modra X-Patchwork-Id: 370626 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 31A84140116 for ; Wed, 16 Jul 2014 18:04:36 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; q=dns; s=default; b=FB5HVXeFcb90ycM1/F7Q2tVpYAjPG /Y8Ww2aqPd/iovi/mily48jt4/g+iQG5WlNxPymfUe3B7Af5s6KbAlWUEppBk0OL 642C4VRLCmmAQJh8PShdmhAflkv4WxCh0t0dHcQ3lTEo4lePGC8+11fga/5mHDXO sAQ4qy+VnDiiTE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; s=default; bh=getFgHKRJXmX39NfdqP3p+7Gu4s=; b=dTw 5PSjVJtk4SxsAsb8psH//AB7xLI9wEsht2nCUkGbtbLCOgOxGOzBL7je7YZVgW34 qZdklV6bpGBxLYA6DVszNkEwJ29RIEqNko0fmW7NjoQAYQS96l3gCdciKk9mrklZ nun2dmcJA2k0yY1QCiFgnVhjP7HQxOEGxERCQwRA= Received: (qmail 10220 invoked by alias); 16 Jul 2014 08:04:30 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 10210 invoked by uid 89); 16 Jul 2014 08:04:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f169.google.com X-Received: by 10.70.38.1 with SMTP id c1mr19426296pdk.108.1405497857992; Wed, 16 Jul 2014 01:04:17 -0700 (PDT) Date: Wed, 16 Jul 2014 17:34:12 +0930 From: Alan Modra To: libc-alpha@sourceware.org Subject: 64-bit obstack support Message-ID: <20140716080412.GB8039@bubble.grove.modra.org> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) In https://sourceware.org/ml/binutils/2014-07/msg00137.html, I bumped OBSTACK_INTERFACE_VERSION, thinking that with an int -> size_t change on some function parameters we obviously have an ABI change. However, it seems that the bump is not really necessary due to the following: - the existing obstack support only works for obstacks sized up to INTMAX, so we only need to be compatible if passing a size_t in the positive int range. - on 32-bit targets supported by glibc, sizeof(int) == sizeof(size_t), so for those targets the change is just substituting an unsigned parameter for one that was signed. - on 64-bit targets supported by glibc, a size_t parameter (at least for the first or second parameter) or return from a function, is passed in the same register as an int. I checked aarch64, alpha, mips64, powerpc64, s390x, sh64, sparc64, tilegx, x64_64. That leaves non-glibc supported targets to consider, but I wonder if they are worth worrying about.. I expect that most modern 64-bit targets would prove to be similar in that int and size_t are passed to functions in registers. Note that in contrast to my previous patch, this one does not make obstack.chunk_size a size_t, over concern that x86_64-mingw would see an ABI change if I did that. Comments? (Maybe at the Cauldron, I'm about to catch a plane!) PR gdb/17133 * malloc/obstack.h: Formatting. Test HAVE_STRING_H. (__PTR_INT_TYPE): Rename from PTR_INT_TYPE. (__attribute_pure__): Define without reference to glibc macro. (__extension__): Avoid warning when __GNUC_MINOR__ undefined. (struct obstack): Make chunk_size unsigned long, and temp union with size_t. Correct chunkfun prototype to take a size_t. (_obstack_newchunk): Update prototype. (_obstack_begin, _obstack_begin_1, _obstack_memory_used): Likewise. (__obstack_free): Define as _obstack_free. (obstack_init, obstack_begin, obstack_specify_allocation_with_arg, obstack_chunkfun): Update alloc function casts, formatting. For __STDC__ versions of the following macros: (obstack_object_size): Return size_t. (obstack_room): Likewise, and rename __o. (obstack_make_room): Make __len size_t, and use obstack_room. (obstack_grow, obstack_grow0, obstack_1grow, obstack_ptr_grow, obstack_int_grow, obstack_blank): Likewise. (obstack_finish): Use unsigned comparison when comparing aligned next_free against chunk_limit. (obstack_free): Cast OBJ to remove possible const qualifier. Don't wrap __obstack_free in parentheses. For !__STDC__ versions of the following macros: (obstack_object_size, obstack_room): Return size_t. (obstack_make_room): Use temp.i and obstack_room. (obstack_grow, obstack_grow0, obstack_1grow, obstack_ptr_grow, obstack_int_grow, obstack_blank): Likewise. (obstack_finish): Use temp.p. Use unsigned comparision when comparing aligned next_free against chunk_limit. (obstack_free): Use temp.p and same comparisons as __STDC__ version. Don't wrap __obstack_free in parentheses. * malloc/obstack.c: Test HAVE_CONFIG_H. Include gnu-versions.h. (COPYING_UNIT): Delete. (_Noreturn): Don't rely on this being defined, define .. (__attribute_noreturn__): ..and use this instead. (CALL_CHUNKFUN): Update chunkfun cast. (chunkfun_t, freefun_t): New typdefs. (_obstack_begin_worker): Split out from .. (_obstack_begin, _obstack_begin_1): ..here. Make "size" param unsigned long, and correct chunkfun prototype. (_obstack_newchunk): Make "length" param size_t and local vars size_t. Use memcpy to move existing object. (obstack_free): Update alias. (_obstack_memory_used): Return and use size_t local. diff --git a/malloc/obstack.h b/malloc/obstack.h index 59ae6e5..be64816 100644 --- a/malloc/obstack.h +++ b/malloc/obstack.h @@ -96,7 +96,7 @@ Because of the way we do it, you can "unwind" an obstack back to a previous state. (You may remove objects much as you would with a stack.) - */ +*/ /* Don't do the contents of this file more than once. */ @@ -110,10 +110,10 @@ and use ptrdiff_t. */ #ifdef __PTRDIFF_TYPE__ -# define PTR_INT_TYPE __PTRDIFF_TYPE__ +# define __PTR_INT_TYPE __PTRDIFF_TYPE__ #else # include -# define PTR_INT_TYPE ptrdiff_t +# define __PTR_INT_TYPE ptrdiff_t #endif /* If B is the base of an object addressed by P, return the result of @@ -122,77 +122,88 @@ #define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A))) -/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case +/* Similar to __BPTR_ALIGN (B, P, A), except optimize the common case where pointers can be converted to integers, aligned as integers, - and converted back again. If PTR_INT_TYPE is narrower than a + and converted back again. If __PTR_INT_TYPE is narrower than a pointer (e.g., the AS/400), play it safe and compute the alignment relative to B. Otherwise, use the faster strategy of computing the alignment relative to 0. */ #define __PTR_ALIGN(B, P, A) \ - __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \ + __BPTR_ALIGN (sizeof (__PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \ P, A) -#include +#if defined _LIBC || defined HAVE_STRING_H +# include +#endif +/* Attribute 'pure' was valid as of gcc 3.0. */ #ifndef __attribute_pure__ -# define __attribute_pure__ _GL_ATTRIBUTE_PURE +# if defined __GNUC__ && __GNUC__ >= 3 +# define __attribute_pure__ __attribute__ ((__pure__)) +# else +# define __attribute_pure__ +# endif #endif #ifdef __cplusplus extern "C" { #endif -struct _obstack_chunk /* Lives at front of each chunk. */ +struct _obstack_chunk /* Lives at front of each chunk. */ { - char *limit; /* 1 past end of this chunk */ - struct _obstack_chunk *prev; /* address of prior chunk or NULL */ - char contents[4]; /* objects begin here */ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ }; -struct obstack /* control current object in current chunk */ +struct obstack /* control current object in current chunk */ { - long chunk_size; /* preferred size to allocate chunks in */ - struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ - char *object_base; /* address of object we are building */ - char *next_free; /* where to add next char to current object */ - char *chunk_limit; /* address of char after current chunk */ + unsigned long chunk_size; /* Initial chunk size. Should be a size_t, + along with the 2nd. arg of obstack_begin*, + but we can't change without bumping the ABI. + Some targets, eg. x64_64-mingw, have a + 32-bit long and 64-bit size_t. */ + struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ union { - PTR_INT_TYPE tempint; - void *tempptr; - } temp; /* Temporary for some macros. */ - int alignment_mask; /* Mask of alignment for each object. */ + size_t i; + void *p; + } temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ /* These prototypes vary based on 'use_extra_arg', and we use casts to the prototypeless function type in all assignments, but having prototypes here quiets -Wstrict-prototypes. */ - struct _obstack_chunk *(*chunkfun) (void *, long); + struct _obstack_chunk *(*chunkfun) (void *, size_t); void (*freefun) (void *, struct _obstack_chunk *); - void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ - unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */ + void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ + unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */ unsigned maybe_empty_object : 1; /* There is a possibility that the current chunk contains a zero-length object. This prevents freeing the chunk if we allocate a bigger chunk to replace it. */ - unsigned alloc_failed : 1; /* No longer used, as we now call the failed + unsigned alloc_failed : 1; /* No longer used, as we now call the failed handler on error, but retained for binary compatibility. */ }; /* Declare the external functions we use; they are in obstack.c. */ -extern void _obstack_newchunk (struct obstack *, int); -extern int _obstack_begin (struct obstack *, int, int, - void *(*)(long), void (*)(void *)); -extern int _obstack_begin_1 (struct obstack *, int, int, - void *(*)(void *, long), - void (*)(void *, void *), void *); -extern int _obstack_memory_used (struct obstack *) __attribute_pure__; +extern void _obstack_newchunk (struct obstack *, size_t); +extern int _obstack_begin (struct obstack *, unsigned long, int, + void *(*) (size_t), void (*) (void *)); +extern int _obstack_begin_1 (struct obstack *, unsigned long, int, + void *(*) (void *, size_t), + void (*) (void *, void *), void *); +extern size_t _obstack_memory_used (struct obstack *) __attribute_pure__; -/* The default name of the function for freeing a chunk is 'obstack_free', +/* The default name of the function for freeing a chunk is '_obstack_free', but gnulib users can override this by defining '__obstack_free'. */ #ifndef __obstack_free -# define __obstack_free obstack_free +# define __obstack_free _obstack_free #endif extern void __obstack_free (struct obstack *, void *); @@ -218,38 +229,38 @@ extern int obstack_exit_failure; /* Pointer to next byte not yet allocated in current chunk. */ -#define obstack_next_free(h) ((h)->next_free) +#define obstack_next_free(h) ((h)->next_free) /* Mask specifying low bits that should be clear in address of an object. */ #define obstack_alignment_mask(h) ((h)->alignment_mask) /* To prevent prototype warnings provide complete argument list. */ -#define obstack_init(h) \ - _obstack_begin ((h), 0, 0, \ - (void *(*)(long))obstack_chunk_alloc, \ - (void (*)(void *))obstack_chunk_free) +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) (size_t)) obstack_chunk_alloc, \ + (void (*) (void *)) obstack_chunk_free) -#define obstack_begin(h, size) \ - _obstack_begin ((h), (size), 0, \ - (void *(*)(long))obstack_chunk_alloc, \ - (void (*)(void *))obstack_chunk_free) +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) (size_t)) obstack_chunk_alloc, \ + (void (*) (void *)) obstack_chunk_free) -#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ - _obstack_begin ((h), (size), (alignment), \ - (void *(*)(long))(chunkfun), \ - (void (*)(void *))(freefun)) +#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) (size_t)) (chunkfun), \ + (void (*) (void *)) (freefun)) #define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ - _obstack_begin_1 ((h), (size), (alignment), \ - (void *(*)(void *, long))(chunkfun), \ - (void (*)(void *, void *))(freefun), (arg)) + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) (void *, size_t)) (chunkfun), \ + (void (*) (void *, void *)) (freefun), (arg)) #define obstack_chunkfun(h, newchunkfun) \ - ((h)->chunkfun = (struct _obstack_chunk *(*)(void *, long))(newchunkfun)) + ((h)->chunkfun = (struct _obstack_chunk *(*)(void *, size_t)) (newchunkfun)) #define obstack_freefun(h, newfreefun) \ - ((h)->freefun = (void (*)(void *, struct _obstack_chunk *))(newfreefun)) + ((h)->freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun)) #define obstack_1grow_fast(h, achar) (*((h)->next_free)++ = (achar)) @@ -258,7 +269,7 @@ extern int obstack_exit_failure; #define obstack_memory_used(h) _obstack_memory_used (h) #if defined __GNUC__ -# if ! (2 < __GNUC__ + (8 <= __GNUC_MINOR__)) +# if !defined __GNUC_MINOR__ || __GNUC__ * 1000 + __GNUC_MINOR__ < 2008 # define __extension__ # endif @@ -267,159 +278,160 @@ extern int obstack_exit_failure; without using a global variable. Also, we can avoid using the 'temp' slot, to make faster code. */ -# define obstack_object_size(OBSTACK) \ - __extension__ \ - ({ struct obstack const *__o = (OBSTACK); \ - (unsigned) (__o->next_free - __o->object_base); }) - -# define obstack_room(OBSTACK) \ - __extension__ \ - ({ struct obstack const *__o = (OBSTACK); \ - (unsigned) (__o->chunk_limit - __o->next_free); }) - -# define obstack_make_room(OBSTACK, length) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - int __len = (length); \ - if (__o->chunk_limit - __o->next_free < __len) \ - _obstack_newchunk (__o, __len); \ - (void) 0; }) - -# define obstack_empty_p(OBSTACK) \ - __extension__ \ - ({ struct obstack const *__o = (OBSTACK); \ - (__o->chunk->prev == 0 \ - && __o->next_free == __PTR_ALIGN ((char *) __o->chunk, \ - __o->chunk->contents, \ - __o->alignment_mask)); }) - -# define obstack_grow(OBSTACK, where, length) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - int __len = (length); \ - if (__o->next_free + __len > __o->chunk_limit) \ - _obstack_newchunk (__o, __len); \ - memcpy (__o->next_free, where, __len); \ - __o->next_free += __len; \ - (void) 0; }) - -# define obstack_grow0(OBSTACK, where, length) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - int __len = (length); \ - if (__o->next_free + __len + 1 > __o->chunk_limit) \ - _obstack_newchunk (__o, __len + 1); \ - memcpy (__o->next_free, where, __len); \ - __o->next_free += __len; \ - *(__o->next_free)++ = 0; \ - (void) 0; }) - -# define obstack_1grow(OBSTACK, datum) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - if (__o->next_free + 1 > __o->chunk_limit) \ - _obstack_newchunk (__o, 1); \ - obstack_1grow_fast (__o, datum); \ - (void) 0; }) +# define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (size_t) (__o->next_free - __o->object_base); }) + +/* The local variable is named __o1 to avoid a shadowed variable + warning when invoked from other obstack macros. */ +# define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o1 = (OBSTACK); \ + (size_t) (__o1->chunk_limit - __o1->next_free); }) + +# define obstack_make_room(OBSTACK, length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + size_t __len = (length); \ + if (obstack_room (__o) < __len) \ + _obstack_newchunk (__o, __len); \ + (void) 0; }) + +# define obstack_empty_p(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (__o->chunk->prev == 0 \ + && __o->next_free == __PTR_ALIGN ((char *) __o->chunk, \ + __o->chunk->contents, \ + __o->alignment_mask)); }) + +# define obstack_grow(OBSTACK, where, length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + size_t __len = (length); \ + if (obstack_room (__o) < __len) \ + _obstack_newchunk (__o, __len); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +# define obstack_grow0(OBSTACK, where, length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + size_t __len = (length); \ + if (obstack_room (__o) < __len + 1) \ + _obstack_newchunk (__o, __len + 1); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +# define obstack_1grow(OBSTACK, datum) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + if (obstack_room (__o) < 1) \ + _obstack_newchunk (__o, 1); \ + obstack_1grow_fast (__o, datum); \ + (void) 0; }) /* These assume that the obstack alignment is good enough for pointers or ints, and that the data added so far to the current object shares that much alignment. */ -# define obstack_ptr_grow(OBSTACK, datum) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ - _obstack_newchunk (__o, sizeof (void *)); \ - obstack_ptr_grow_fast (__o, datum); }) \ - -# define obstack_int_grow(OBSTACK, datum) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - if (__o->next_free + sizeof (int) > __o->chunk_limit) \ - _obstack_newchunk (__o, sizeof (int)); \ - obstack_int_grow_fast (__o, datum); }) - -# define obstack_ptr_grow_fast(OBSTACK, aptr) \ - __extension__ \ - ({ struct obstack *__o1 = (OBSTACK); \ - void *__p1 = __o1->next_free; \ - *(const void **) __p1 = (aptr); \ - __o1->next_free += sizeof (const void *); \ - (void) 0; }) - -# define obstack_int_grow_fast(OBSTACK, aint) \ - __extension__ \ - ({ struct obstack *__o1 = (OBSTACK); \ - void *__p1 = __o1->next_free; \ - *(int *) __p1 = (aint); \ - __o1->next_free += sizeof (int); \ - (void) 0; }) - -# define obstack_blank(OBSTACK, length) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - int __len = (length); \ - if (__o->chunk_limit - __o->next_free < __len) \ - _obstack_newchunk (__o, __len); \ - obstack_blank_fast (__o, __len); \ - (void) 0; }) - -# define obstack_alloc(OBSTACK, length) \ - __extension__ \ - ({ struct obstack *__h = (OBSTACK); \ - obstack_blank (__h, (length)); \ - obstack_finish (__h); }) - -# define obstack_copy(OBSTACK, where, length) \ - __extension__ \ - ({ struct obstack *__h = (OBSTACK); \ - obstack_grow (__h, (where), (length)); \ - obstack_finish (__h); }) - -# define obstack_copy0(OBSTACK, where, length) \ - __extension__ \ - ({ struct obstack *__h = (OBSTACK); \ - obstack_grow0 (__h, (where), (length)); \ - obstack_finish (__h); }) - -/* The local variable is named __o1 to avoid a name conflict - when obstack_blank is called. */ -# define obstack_finish(OBSTACK) \ - __extension__ \ - ({ struct obstack *__o1 = (OBSTACK); \ - void *__value = (void *) __o1->object_base; \ - if (__o1->next_free == __value) \ - __o1->maybe_empty_object = 1; \ - __o1->next_free \ - = __PTR_ALIGN (__o1->object_base, __o1->next_free, \ - __o1->alignment_mask); \ - if (__o1->next_free - (char *) __o1->chunk \ - > __o1->chunk_limit - (char *) __o1->chunk) \ - __o1->next_free = __o1->chunk_limit; \ - __o1->object_base = __o1->next_free; \ - __value; }) - -# define obstack_free(OBSTACK, OBJ) \ - __extension__ \ - ({ struct obstack *__o = (OBSTACK); \ - void *__obj = (OBJ); \ - if (__obj > (void *) __o->chunk && __obj < (void *) __o->chunk_limit) \ - __o->next_free = __o->object_base = (char *) __obj; \ - else (__obstack_free) (__o, __obj); }) +# define obstack_ptr_grow(OBSTACK, datum) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + if (obstack_room (__o) < sizeof (void *)) \ + _obstack_newchunk (__o, sizeof (void *)); \ + obstack_ptr_grow_fast (__o, datum); }) + +# define obstack_int_grow(OBSTACK, datum) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + if (obstack_room (__o) < sizeof (int)) \ + _obstack_newchunk (__o, sizeof (int)); \ + obstack_int_grow_fast (__o, datum); }) + +# define obstack_ptr_grow_fast(OBSTACK, aptr) \ + __extension__ \ + ({ struct obstack *__o1 = (OBSTACK); \ + void *__p1 = __o1->next_free; \ + *(const void **) __p1 = (aptr); \ + __o1->next_free += sizeof (const void *); \ + (void) 0; }) + +# define obstack_int_grow_fast(OBSTACK, aint) \ + __extension__ \ + ({ struct obstack *__o1 = (OBSTACK); \ + void *__p1 = __o1->next_free; \ + *(int *) __p1 = (aint); \ + __o1->next_free += sizeof (int); \ + (void) 0; }) + +# define obstack_blank(OBSTACK, length) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + size_t __len = (length); \ + if (obstack_room (__o) < __len) \ + _obstack_newchunk (__o, __len); \ + obstack_blank_fast (__o, __len); \ + (void) 0; }) + +# define obstack_alloc(OBSTACK, length) \ + __extension__ \ + ({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +# define obstack_copy(OBSTACK, where, length) \ + __extension__ \ + ({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +# define obstack_copy0(OBSTACK, where, length) \ + __extension__ \ + ({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +# define obstack_finish(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o1 = (OBSTACK); \ + void *__value = (void *) __o1->object_base; \ + if (__o1->next_free == __value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free = __PTR_ALIGN (__o1->object_base, __o1->next_free, \ + __o1->alignment_mask); \ + if ((size_t) (__o1->next_free - (char *) __o1->chunk) \ + > (size_t) (__o1->chunk_limit - (char *) __o1->chunk)) \ + __o1->next_free = __o1->chunk_limit; \ + __o1->object_base = __o1->next_free; \ + __value; }) + +# define obstack_free(OBSTACK, OBJ) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + void *__obj = (void *) (OBJ); \ + if (__obj > (void *) __o->chunk \ + && __obj < (void *) __o->chunk_limit) \ + __o->next_free = __o->object_base = (char *) __obj; \ + else \ + __obstack_free (__o, __obj); }) #else /* not __GNUC__ */ # define obstack_object_size(h) \ - (unsigned) ((h)->next_free - (h)->object_base) + ((size_t) ((h)->next_free - (h)->object_base)) -# define obstack_room(h) \ - (unsigned) ((h)->chunk_limit - (h)->next_free) +# define obstack_room(h) \ + ((size_t) ((h)->chunk_limit - (h)->next_free)) # define obstack_empty_p(h) \ - ((h)->chunk->prev == 0 \ - && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk, \ - (h)->chunk->contents, \ + ((h)->chunk->prev == 0 \ + && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk, \ + (h)->chunk->contents, \ (h)->alignment_mask)) /* Note that the call to _obstack_newchunk is enclosed in (..., 0) @@ -427,89 +439,86 @@ extern int obstack_exit_failure; in the arms of the conditional expression. Casting the third operand to void was tried before, but some compilers won't accept it. */ - -# define obstack_make_room(h, length) \ - ((h)->temp.tempint = (length), \ - (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \ - ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0)) - -# define obstack_grow(h, where, length) \ - ((h)->temp.tempint = (length), \ - (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \ - ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \ - memcpy ((h)->next_free, where, (h)->temp.tempint), \ - (h)->next_free += (h)->temp.tempint) - -# define obstack_grow0(h, where, length) \ - ((h)->temp.tempint = (length), \ - (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit) \ - ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0), \ - memcpy ((h)->next_free, where, (h)->temp.tempint), \ - (h)->next_free += (h)->temp.tempint, \ +# define obstack_make_room(h, length) \ + ((h)->temp.i = (length), \ + ((obstack_room (h) < (h)->temp.i) \ + ? (_obstack_newchunk ((h), (h)->temp.i), 0) : 0)) + +# define obstack_grow(h, where, length) \ + ((h)->temp.i = (length), \ + ((obstack_room (h) < (h)->temp.i) \ + ? (_obstack_newchunk ((h), (h)->temp.i), 0) : 0), \ + memcpy ((h)->next_free, where, (h)->temp.i), \ + (h)->next_free += (h)->temp.i) + +# define obstack_grow0(h, where, length) \ + ((h)->temp.i = (length), \ + ((obstack_room (h) < (h)->temp.i + 1) \ + ? (_obstack_newchunk ((h), (h)->temp.i + 1), 0) : 0), \ + memcpy ((h)->next_free, where, (h)->temp.i), \ + (h)->next_free += (h)->temp.i, \ *((h)->next_free)++ = 0) -# define obstack_1grow(h, datum) \ - ((((h)->next_free + 1 > (h)->chunk_limit) \ - ? (_obstack_newchunk ((h), 1), 0) : 0), \ +# define obstack_1grow(h, datum) \ + (((obstack_room (h) < 1) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ obstack_1grow_fast (h, datum)) -# define obstack_ptr_grow(h, datum) \ - ((((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ - ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ +# define obstack_ptr_grow(h, datum) \ + ((((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ obstack_ptr_grow_fast (h, datum)) -# define obstack_int_grow(h, datum) \ - ((((h)->next_free + sizeof (int) > (h)->chunk_limit) \ - ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ +# define obstack_int_grow(h, datum) \ + (((obstack_room (h) < sizeof (int)) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ obstack_int_grow_fast (h, datum)) -# define obstack_ptr_grow_fast(h, aptr) \ +# define obstack_ptr_grow_fast(h, aptr) \ (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr)) -# define obstack_int_grow_fast(h, aint) \ +# define obstack_int_grow_fast(h, aint) \ (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint)) -# define obstack_blank(h, length) \ - ((h)->temp.tempint = (length), \ - (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint) \ - ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \ - obstack_blank_fast (h, (h)->temp.tempint)) +# define obstack_blank(h, length) \ + ((h)->temp.i = (length), \ + ((obstack_room (h) < (h)->temp.i) \ + ? (_obstack_newchunk ((h), (h)->temp.i), 0) : 0), \ + obstack_blank_fast (h, (h)->temp.i)) -# define obstack_alloc(h, length) \ +# define obstack_alloc(h, length) \ (obstack_blank ((h), (length)), obstack_finish ((h))) -# define obstack_copy(h, where, length) \ +# define obstack_copy(h, where, length) \ (obstack_grow ((h), (where), (length)), obstack_finish ((h))) -# define obstack_copy0(h, where, length) \ +# define obstack_copy0(h, where, length) \ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) -# define obstack_finish(h) \ - (((h)->next_free == (h)->object_base \ - ? (((h)->maybe_empty_object = 1), 0) \ - : 0), \ - (h)->temp.tempptr = (h)->object_base, \ - (h)->next_free \ - = __PTR_ALIGN ((h)->object_base, (h)->next_free, \ - (h)->alignment_mask), \ - (((h)->next_free - (char *) (h)->chunk \ - > (h)->chunk_limit - (char *) (h)->chunk) \ - ? ((h)->next_free = (h)->chunk_limit) : 0), \ - (h)->object_base = (h)->next_free, \ - (h)->temp.tempptr) - -# define obstack_free(h, obj) \ - ((h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk, \ - ((((h)->temp.tempint > 0 \ - && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk)) \ - ? (void) ((h)->next_free = (h)->object_base \ - = (h)->temp.tempint + (char *) (h)->chunk) \ - : (__obstack_free) (h, (h)->temp.tempint + (char *) (h)->chunk))) +# define obstack_finish(h) \ + (((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp.p = (h)->object_base, \ + (h)->next_free = __PTR_ALIGN ((h)->object_base, (h)->next_free, \ + (h)->alignment_mask), \ + (((size_t) ((h)->next_free - (char *) (h)->chunk) \ + > (size_t) ((h)->chunk_limit - (char *) (h)->chunk)) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + (h)->temp.p) + +# define obstack_free(h, obj) \ + ((h)->temp.p = (void *) (obj), \ + (((h)->temp.p > (void *) (h)->chunk \ + && (h)->temp.p < (void *) (h)->chunk_limit) \ + ? (void) ((h)->next_free = (h)->object_base = (char *) (h)->temp.p) \ + : __obstack_free ((h), (h)->temp.p))) #endif /* not __GNUC__ */ #ifdef __cplusplus -} /* C++ */ +} /* C++ */ #endif -#endif /* obstack.h */ +#endif /* _OBSTACK_H */ diff --git a/malloc/obstack.c b/malloc/obstack.c index fa4fefc..1838115 100644 --- a/malloc/obstack.c +++ b/malloc/obstack.c @@ -21,7 +21,9 @@ # include # include #else -# include +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif # include "obstack.h" #endif @@ -47,11 +49,9 @@ # endif #endif -#include - #ifndef ELIDE_CODE - +# include # include /* Determine default alignment. */ @@ -75,22 +75,22 @@ enum DEFAULT_ROUNDING = sizeof (union fooround) }; -/* When we copy a long block of data, this is the unit to do it with. - On some machines, copying successive ints does not work; - in such a case, redefine COPYING_UNIT to 'long' (if that works) - or 'char' as a last resort. */ -# ifndef COPYING_UNIT -# define COPYING_UNIT int -# endif - - /* The functions allocating more room by calling 'obstack_chunk_alloc' jump to the handler pointed to by 'obstack_alloc_failed_handler'. This can be set to a user defined function which should either abort gracefully or use longjump - but shouldn't return. This variable by default points to the internal function 'print_and_abort'. */ -static _Noreturn void print_and_abort (void); + +# ifndef __attribute_noreturn__ +# if (defined __GNUC__ && defined __GNUC_MINOR__ \ + && __GNUC__ * 1000 + __GNUC_MINOR__ >= 2007) +# define __attribute_noreturn__ __attribute__ ((__noreturn__)) +# else +# define __attribute_noreturn__ +# endif +# endif +static void __attribute_noreturn__ print_and_abort (void); void (*obstack_alloc_failed_handler) (void) = print_and_abort; /* Exit value used when 'print_and_abort' is used. */ @@ -119,17 +119,17 @@ compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0); do not allow (expr) ? void : void. */ # define CALL_CHUNKFUN(h, size) \ - (((h)->use_extra_arg) \ - ? (*(h)->chunkfun)((h)->extra_arg, (size)) \ - : (*(struct _obstack_chunk *(*)(long))(h)->chunkfun)((size))) + (((h)->use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(struct _obstack_chunk *(*) (size_t)) (h)->chunkfun) ((size))) # define CALL_FREEFUN(h, old_chunk) \ - do { \ - if ((h)->use_extra_arg) \ - (*(h)->freefun)((h)->extra_arg, (old_chunk)); \ - else \ - (*(void (*)(void *))(h)->freefun)((old_chunk)); \ - } while (0) + do { \ + if ((h)->use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \ + } while (0) /* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). @@ -140,11 +140,14 @@ compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0); Return nonzero if successful, calls obstack_alloc_failed_handler if allocation fails. */ -int -_obstack_begin (struct obstack *h, - int size, int alignment, - void *(*chunkfun) (long), - void (*freefun) (void *)) +typedef struct _obstack_chunk * (*chunkfun_t) (void *, size_t); +typedef void (*freefun_t) (void *, struct _obstack_chunk *); + +static int +_obstack_begin_worker (struct obstack *h, + unsigned long size, int alignment, + chunkfun_t chunkfun, freefun_t freefun, + void *arg, int use_extra_arg) { struct _obstack_chunk *chunk; /* points to new chunk */ @@ -167,19 +170,19 @@ _obstack_begin (struct obstack *h, size = 4096 - extra; } - h->chunkfun = (struct _obstack_chunk * (*) (void *, long)) chunkfun; - h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunkfun = chunkfun; + h->freefun = freefun; h->chunk_size = size; h->alignment_mask = alignment - 1; - h->use_extra_arg = 0; + h->extra_arg = arg; + h->use_extra_arg = use_extra_arg; chunk = h->chunk = CALL_CHUNKFUN (h, h->chunk_size); if (!chunk) (*obstack_alloc_failed_handler) (); h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents, alignment - 1); - h->chunk_limit = chunk->limit - = (char *) chunk + h->chunk_size; + h->chunk_limit = chunk->limit = (char *) chunk + h->chunk_size; chunk->prev = 0; /* The initial chunk now contains no empty object. */ h->maybe_empty_object = 0; @@ -188,51 +191,26 @@ _obstack_begin (struct obstack *h, } int -_obstack_begin_1 (struct obstack *h, int size, int alignment, - void *(*chunkfun) (void *, long), +_obstack_begin (struct obstack *h, + unsigned long size, int alignment, + void *(*chunkfun) (size_t), + void (*freefun) (void *)) +{ + return _obstack_begin_worker (h, size, alignment, + (chunkfun_t) chunkfun, (freefun_t) freefun, + NULL, 0); +} + +int +_obstack_begin_1 (struct obstack *h, + unsigned long size, int alignment, + void *(*chunkfun) (void *, size_t), void (*freefun) (void *, void *), void *arg) { - struct _obstack_chunk *chunk; /* points to new chunk */ - - if (alignment == 0) - alignment = DEFAULT_ALIGNMENT; - if (size == 0) - /* Default size is what GNU malloc can fit in a 4096-byte block. */ - { - /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. - Use the values for range checking, because if range checking is off, - the extra bytes won't be missed terribly, but if range checking is on - and we used a larger request, a whole extra 4096 bytes would be - allocated. - - These number are irrelevant to the new GNU malloc. I suspect it is - less sensitive to the size of the request. */ - int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) - + 4 + DEFAULT_ROUNDING - 1) - & ~(DEFAULT_ROUNDING - 1)); - size = 4096 - extra; - } - - h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun; - h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; - h->chunk_size = size; - h->alignment_mask = alignment - 1; - h->extra_arg = arg; - h->use_extra_arg = 1; - - chunk = h->chunk = CALL_CHUNKFUN (h, h->chunk_size); - if (!chunk) - (*obstack_alloc_failed_handler) (); - h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents, - alignment - 1); - h->chunk_limit = chunk->limit - = (char *) chunk + h->chunk_size; - chunk->prev = 0; - /* The initial chunk now contains no empty object. */ - h->maybe_empty_object = 0; - h->alloc_failed = 0; - return 1; + return _obstack_begin_worker (h, size, alignment, + (chunkfun_t) chunkfun, (freefun_t) freefun, + arg, 1); } /* Allocate a new current chunk for the obstack *H @@ -242,14 +220,12 @@ _obstack_begin_1 (struct obstack *h, int size, int alignment, to the beginning of the new one. */ void -_obstack_newchunk (struct obstack *h, int length) +_obstack_newchunk (struct obstack *h, size_t length) { struct _obstack_chunk *old_chunk = h->chunk; struct _obstack_chunk *new_chunk; - long new_size; - long obj_size = h->next_free - h->object_base; - long i; - long already; + size_t new_size; + size_t obj_size = h->next_free - h->object_base; char *object_base; /* Compute size for new chunk. */ @@ -260,7 +236,7 @@ _obstack_newchunk (struct obstack *h, int length) /* Allocate and initialize the new chunk. */ new_chunk = CALL_CHUNKFUN (h, new_size); if (!new_chunk) - (*obstack_alloc_failed_handler)(); + (*obstack_alloc_failed_handler) (); h->chunk = new_chunk; new_chunk->prev = old_chunk; new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; @@ -269,25 +245,8 @@ _obstack_newchunk (struct obstack *h, int length) object_base = __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask); - /* Move the existing object to the new chunk. - Word at a time is fast and is safe if the object - is sufficiently aligned. */ - if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) - { - for (i = obj_size / sizeof (COPYING_UNIT) - 1; - i >= 0; i--) - ((COPYING_UNIT *) object_base)[i] - = ((COPYING_UNIT *) h->object_base)[i]; - /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, - but that can cross a page boundary on a machine - which does not do strict alignment for COPYING_UNITS. */ - already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); - } - else - already = 0; - /* Copy remaining bytes one by one. */ - for (i = already; i < obj_size; i++) - object_base[i] = h->object_base[i]; + /* Move the existing object to the new chunk. */ + memcpy (object_base, h->object_base, obj_size); /* If the object just copied was the only data in OLD_CHUNK, free that chunk and remove it from the chain. @@ -321,8 +280,8 @@ int _obstack_allocated_p (struct obstack *h, void *obj) __attribute_pure__; int _obstack_allocated_p (struct obstack *h, void *obj) { - struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ - struct _obstack_chunk *plp; /* point to previous chunk if any */ + struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + struct _obstack_chunk *plp; /* point to previous chunk if any */ lp = (h)->chunk; /* We use >= rather than > since the object cannot be exactly at @@ -344,8 +303,8 @@ _obstack_allocated_p (struct obstack *h, void *obj) void __obstack_free (struct obstack *h, void *obj) { - struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ - struct _obstack_chunk *plp; /* point to previous chunk if any */ + struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + struct _obstack_chunk *plp; /* point to previous chunk if any */ lp = h->chunk; /* We use >= because there cannot be an object at the beginning of a chunk. @@ -372,21 +331,19 @@ __obstack_free (struct obstack *h, void *obj) } # ifdef _LIBC -/* Older versions of libc used a function _obstack_free intended to be - called by non-GCC compilers. */ -strong_alias (obstack_free, _obstack_free) +/* Older versions of libc declared both _obstack_free and obstack_free. */ +strong_alias (__obstack_free, obstack_free) # endif -int +size_t _obstack_memory_used (struct obstack *h) { struct _obstack_chunk *lp; - int nbytes = 0; + size_t nbytes = 0; for (lp = h->chunk; lp != 0; lp = lp->prev) - { - nbytes += lp->limit - (char *) lp; - } + nbytes += lp->limit - (char *) lp; + return nbytes; } @@ -404,7 +361,8 @@ _obstack_memory_used (struct obstack *h) # include # endif -static _Noreturn void +static void +__attribute_noreturn__ print_and_abort (void) { /* Don't change any of these strings. Yes, it would be possible to add @@ -420,4 +378,4 @@ print_and_abort (void) exit (obstack_exit_failure); } -#endif /* !ELIDE_CODE */ +#endif /* !ELIDE_CODE */