diff --git a/src/backend/nodes/nodes.c b/src/backend/nodes/nodes.c index 6d1deadb0bbd464f6b5c10624fe3931d0f4396ce..f71bd020ce93a1f3937f7a5acfe4bda87954bbf9 100644 --- a/src/backend/nodes/nodes.c +++ b/src/backend/nodes/nodes.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.18 2002/11/10 02:17:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.19 2002/12/16 16:22:46 tgl Exp $ * * HISTORY * Andrew Yu Oct 20, 1994 file creation @@ -17,16 +17,11 @@ *------------------------------------------------------------------------- */ #include "postgres.h" + #include "nodes/nodes.h" /* - * newNode - - * create a new node of the specified size and tag the node with the - * specified tag. - * - * !WARNING!: Avoid using newNode directly. You should be using the - * macro makeNode. eg. to create a Resdom node, use makeNode(Resdom) - * + * Support for newNode() macro */ -Node *newNodeMacroHolder; +Node *newNodeMacroHolder; diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 9ce0c4ca72fed8742b1230aa6a164f98ad7e56d2..48545b15128fde0f0991be58e88e5e3d79c76d85 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.37 2002/12/15 21:01:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.38 2002/12/16 16:22:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -257,6 +257,35 @@ GetMemoryChunkSpace(void *pointer) pointer); } +/* + * GetMemoryChunkContext + * Given a currently-allocated chunk, determine the context + * it belongs to. + */ +MemoryContext +GetMemoryChunkContext(void *pointer) +{ + StandardChunkHeader *header; + + /* + * Try to detect bogus pointers handed to us, poorly though we can. + * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an + * allocated chunk. + */ + Assert(pointer != NULL); + Assert(pointer == (void *) MAXALIGN(pointer)); + + /* + * OK, it's probably safe to look at the chunk header. + */ + header = (StandardChunkHeader *) + ((char *) pointer - STANDARDCHUNKHEADERSIZE); + + AssertArg(MemoryContextIsValid(header->context)); + + return header->context; +} + /* * MemoryContextStats * Print statistics about the named context and all its descendants. @@ -453,25 +482,52 @@ MemoryContextAlloc(MemoryContext context, Size size) } /* - * MemoryContextAllocPalloc0 + * MemoryContextAllocZero * Like MemoryContextAlloc, but clears allocated memory * * We could just call MemoryContextAlloc then clear the memory, but this - * function is called too many times, so we have a separate version. + * is a very common combination, so we provide the combined operation. */ void * -MemoryContextAllocPalloc0(MemoryContext context, Size size) +MemoryContextAllocZero(MemoryContext context, Size size) { void *ret; AssertArg(MemoryContextIsValid(context)); if (!AllocSizeIsValid(size)) - elog(ERROR, "MemoryContextAllocZero: invalid request size %lu", + elog(ERROR, "MemoryContextAlloc: invalid request size %lu", (unsigned long) size); ret = (*context->methods->alloc) (context, size); + + MemSetAligned(ret, 0, size); + + return ret; +} + +/* + * MemoryContextAllocZeroAligned + * MemoryContextAllocZero where length is suitable for MemSetLoop + * + * This might seem overly specialized, but it's not because newNode() + * is so often called with compile-time-constant sizes. + */ +void * +MemoryContextAllocZeroAligned(MemoryContext context, Size size) +{ + void *ret; + + AssertArg(MemoryContextIsValid(context)); + + if (!AllocSizeIsValid(size)) + elog(ERROR, "MemoryContextAlloc: invalid request size %lu", + (unsigned long) size); + + ret = (*context->methods->alloc) (context, size); + MemSetLoop(ret, 0, size); + return ret; } diff --git a/src/include/c.h b/src/include/c.h index e5d7d6416101bc7a0d0eb89ae9859ffc823bd2a2..040a211a8f15fe4a2449888de47ff626226a1d1d 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: c.h,v 1.133 2002/12/05 04:04:48 momjian Exp $ + * $Id: c.h,v 1.134 2002/12/16 16:22:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -579,38 +579,78 @@ typedef NameData *Name; * memset() functions. More research needs to be done, perhaps with * platform-specific MEMSET_LOOP_LIMIT values or tests in configure. * - * MemSet has been split into two parts so MemSetTest can be optimized - * away for constant 'val' and 'len'. This is used by palloc0(). - * - * Note, arguments are evaluated more than once. - * * bjm 2002-10-08 */ +#define MemSet(start, val, len) \ + do \ + { \ + int32 * _start = (int32 *) (start); \ + int _val = (val); \ + Size _len = (len); \ +\ + if ((((long) _start) & INT_ALIGN_MASK) == 0 && \ + (_len & INT_ALIGN_MASK) == 0 && \ + _val == 0 && \ + _len <= MEMSET_LOOP_LIMIT) \ + { \ + int32 * _stop = (int32 *) ((char *) _start + _len); \ + while (_start < _stop) \ + *_start++ = 0; \ + } \ + else \ + memset((char *) _start, _val, _len); \ + } while (0) + +#define MEMSET_LOOP_LIMIT 1024 + +/* + * MemSetAligned is the same as MemSet except it omits the test to see if + * "start" is word-aligned. This is okay to use if the caller knows a-priori + * that the pointer is suitably aligned (typically, because he just got it + * from palloc(), which always delivers a max-aligned pointer). + */ +#define MemSetAligned(start, val, len) \ + do \ + { \ + int32 * _start = (int32 *) (start); \ + int _val = (val); \ + Size _len = (len); \ +\ + if ((_len & INT_ALIGN_MASK) == 0 && \ + _val == 0 && \ + _len <= MEMSET_LOOP_LIMIT) \ + { \ + int32 * _stop = (int32 *) ((char *) _start + _len); \ + while (_start < _stop) \ + *_start++ = 0; \ + } \ + else \ + memset((char *) _start, _val, _len); \ + } while (0) + + +/* + * MemSetTest/MemSetLoop are a variant version that allow all the tests in + * MemSet to be done at compile time in cases where "val" and "len" are + * constants *and* we know the "start" pointer must be word-aligned. + * If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use + * MemSetAligned. Beware of multiple evaluations of the arguments when using + * this approach. + */ #define MemSetTest(val, len) \ ( ((len) & INT_ALIGN_MASK) == 0 && \ (len) <= MEMSET_LOOP_LIMIT && \ (val) == 0 ) #define MemSetLoop(start, val, len) \ -do \ -{ \ - int32 * _start = (int32 *) (start); \ - int32 * _stop = (int32 *) ((char *) _start + (len)); \ -\ - while (_start < _stop) \ - *_start++ = 0; \ -} while (0) - -#define MemSet(start, val, len) \ -do \ -{ \ - if (MemSetTest(val, len) && ((long)(start) & INT_ALIGN_MASK) == 0 ) \ - MemSetLoop(start, val, len); \ - else \ - memset((char *)(start), (val), (len)); \ -} while (0) - -#define MEMSET_LOOP_LIMIT 1024 + do \ + { \ + int32 * _start = (int32 *) (start); \ + int32 * _stop = (int32 *) ((char *) _start + (Size) (len)); \ + \ + while (_start < _stop) \ + *_start++ = 0; \ + } while (0) /* ---------------------------------------------------------------- diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 5f6281687385f153dc91762b31d4aac06adc7b0a..f119b5111db0976807ec3d7b4b0ddce2899775ac 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nodes.h,v 1.133 2002/12/14 00:17:59 tgl Exp $ + * $Id: nodes.h,v 1.134 2002/12/16 16:22:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -293,9 +293,16 @@ typedef struct Node #define nodeTag(nodeptr) (((Node*)(nodeptr))->type) /* + * newNode - + * create a new node of the specified size and tag the node with the + * specified tag. + * + * !WARNING!: Avoid using newNode directly. You should be using the + * macro makeNode. eg. to create a Query node, use makeNode(Query) + * * There is no way to dereference the palloc'ed pointer to assign the - * tag, and return the pointer itself, so we need a holder variable. - * Fortunately, this function isn't recursive so we just define + * tag, and also return the pointer itself, so we need a holder variable. + * Fortunately, this macro isn't recursive so we just define * a global variable for this purpose. */ extern Node *newNodeMacroHolder; @@ -303,8 +310,7 @@ extern Node *newNodeMacroHolder; #define newNode(size, tag) \ ( \ AssertMacro((size) >= sizeof(Node)), /* need the tag, at least */ \ -\ - newNodeMacroHolder = (Node *) palloc0(size), \ + newNodeMacroHolder = (Node *) palloc0fast(size), \ newNodeMacroHolder->type = (tag), \ newNodeMacroHolder \ ) diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 94578b8fb6fbf42ad68d658f4d47b3743ce3b55a..09198d1c6e60bdc8cc2a85967928d300aa4ad955 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: memutils.h,v 1.49 2002/12/15 21:01:34 tgl Exp $ + * $Id: memutils.h,v 1.50 2002/12/16 16:22:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -83,6 +83,7 @@ extern void MemoryContextResetChildren(MemoryContext context); extern void MemoryContextDeleteChildren(MemoryContext context); extern void MemoryContextResetAndDeleteChildren(MemoryContext context); extern Size GetMemoryChunkSpace(void *pointer); +extern MemoryContext GetMemoryChunkContext(void *pointer); extern void MemoryContextStats(MemoryContext context); #ifdef MEMORY_CONTEXT_CHECKING diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 093764d5ebc2ea39c8b1fd96e4465bb27c95a0cc..7dabc52f318c1df804281b0bac982848a57f79cd 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -21,7 +21,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: palloc.h,v 1.23 2002/11/13 00:37:06 momjian Exp $ + * $Id: palloc.h,v 1.24 2002/12/16 16:22:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -46,15 +46,25 @@ extern DLLIMPORT MemoryContext CurrentMemoryContext; * Fundamental memory-allocation operations (more are in utils/memutils.h) */ extern void *MemoryContextAlloc(MemoryContext context, Size size); -extern void *MemoryContextAllocPalloc0(MemoryContext context, Size size); +extern void *MemoryContextAllocZero(MemoryContext context, Size size); +extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size); #define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz)) -/* We assume palloc() is already int-aligned */ -#define palloc0(sz) \ - ( MemSetTest(0, (sz)) ? \ - MemoryContextAllocPalloc0(CurrentMemoryContext, (sz)) : \ - memset(palloc(sz), 0, (sz))) +#define palloc0(sz) MemoryContextAllocZero(CurrentMemoryContext, (sz)) + +/* + * The result of palloc() is always word-aligned, so we can skip testing + * alignment of the pointer when deciding which MemSet variant to use. + * Note that this variant does not offer any advantage, and should not be + * used, unless its "sz" argument is a compile-time constant; therefore, the + * issue that it evaluates the argument multiple times isn't a problem in + * practice. + */ +#define palloc0fast(sz) \ + ( MemSetTest(0, sz) ? \ + MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \ + MemoryContextAllocZero(CurrentMemoryContext, sz) ) extern void pfree(void *pointer);